diff --git a/webapp/src/lib/i18n/locales/en.ts b/webapp/src/lib/i18n/locales/en.ts
index 97fe7f5..7e50cef 100644
--- a/webapp/src/lib/i18n/locales/en.ts
+++ b/webapp/src/lib/i18n/locales/en.ts
@@ -4,9 +4,12 @@ const en: Record = {
"nav_admin_panel": "Admin Panel",
"nav_device_management": "Device Management",
"nav_my_vault": "My Vault",
+ "nav_vault_items": "Vault",
"nav_sends": "Sends",
"nav_backup_strategy": "Cloud Backup",
"nav_import_export": "Import & Export",
+ "nav_group_data_backup": "Data & Backup",
+ "nav_group_management": "Management",
"txt_page_not_found": "Page Not Found",
"txt_page_not_found_hint": "The page may have been removed, expired, or the link is incomplete.",
"txt_back_to_home": "Back To Home",
diff --git a/webapp/src/lib/i18n/locales/es.ts b/webapp/src/lib/i18n/locales/es.ts
index 9b6f7d7..f01a026 100644
--- a/webapp/src/lib/i18n/locales/es.ts
+++ b/webapp/src/lib/i18n/locales/es.ts
@@ -4,9 +4,12 @@ const es: Record = {
"nav_admin_panel": "Panel de administración",
"nav_device_management": "Gestión de dispositivos",
"nav_my_vault": "Mi bóveda",
+ "nav_vault_items": "Bóveda",
"nav_sends": "Envíos",
"nav_backup_strategy": "Copia de seguridad en la nube",
"nav_import_export": "Importar y exportar",
+ "nav_group_data_backup": "Datos y copias",
+ "nav_group_management": "Gestión",
"txt_page_not_found": "Página no encontrada",
"txt_page_not_found_hint": "La página pudo haberse eliminado, expirado, o el enlace está incompleto.",
"txt_back_to_home": "Volver al inicio",
diff --git a/webapp/src/lib/i18n/locales/ru.ts b/webapp/src/lib/i18n/locales/ru.ts
index 043fb31..587ca7c 100644
--- a/webapp/src/lib/i18n/locales/ru.ts
+++ b/webapp/src/lib/i18n/locales/ru.ts
@@ -5,9 +5,12 @@ const ru: Record = {
"nav_admin_panel": "Панель администратора",
"nav_device_management": "Управление устройствами",
"nav_my_vault": "Мое хранилище",
+ "nav_vault_items": "Хранилище",
"nav_sends": "Отправляет",
"nav_backup_strategy": "Облачное резервное копирование",
"nav_import_export": "Импорт и экспорт",
+ "nav_group_data_backup": "Данные и резервные копии",
+ "nav_group_management": "Управление",
"txt_page_not_found": "Страница не найдена",
"txt_page_not_found_hint": "Страница могла быть удалена, срок ее действия истек, или ссылка неполная.",
"txt_back_to_home": "На главную",
diff --git a/webapp/src/lib/i18n/locales/zh-CN.ts b/webapp/src/lib/i18n/locales/zh-CN.ts
index 6255159..7fd60c6 100644
--- a/webapp/src/lib/i18n/locales/zh-CN.ts
+++ b/webapp/src/lib/i18n/locales/zh-CN.ts
@@ -4,9 +4,12 @@ const zhCN: Record = {
"nav_admin_panel": "用户管理",
"nav_device_management": "设备管理",
"nav_my_vault": "我的密码库",
+ "nav_vault_items": "密码库",
"nav_sends": "Send",
"nav_backup_strategy": "云端备份",
"nav_import_export": "导入导出",
+ "nav_group_data_backup": "数据与备份",
+ "nav_group_management": "管理",
"txt_page_not_found": "页面不存在",
"txt_page_not_found_hint": "这个页面可能已经删除、过期,或者链接不完整。",
"txt_back_to_home": "回到首页",
diff --git a/webapp/src/lib/i18n/locales/zh-TW.ts b/webapp/src/lib/i18n/locales/zh-TW.ts
index 5c755f6..d006879 100644
--- a/webapp/src/lib/i18n/locales/zh-TW.ts
+++ b/webapp/src/lib/i18n/locales/zh-TW.ts
@@ -4,9 +4,12 @@ const zhTW: Record = {
"nav_admin_panel": "用戶管理",
"nav_device_management": "設備管理",
"nav_my_vault": "我的密碼庫",
+ "nav_vault_items": "密碼庫",
"nav_sends": "Send",
"nav_backup_strategy": "雲端備份",
"nav_import_export": "導入導出",
+ "nav_group_data_backup": "資料與備份",
+ "nav_group_management": "管理",
"txt_page_not_found": "頁面不存在",
"txt_page_not_found_hint": "這個頁面可能已經刪除、過期,或者連結不完整。",
"txt_back_to_home": "回到首頁",
diff --git a/webapp/src/styles/shell.css b/webapp/src/styles/shell.css
index 652a565..3be1c35 100644
--- a/webapp/src/styles/shell.css
+++ b/webapp/src/styles/shell.css
@@ -167,6 +167,75 @@
@apply flex items-center gap-2.5 rounded-xl border border-transparent px-3 py-2.5 text-sm font-semibold text-muted-strong no-underline transition;
}
+.side-nav-group {
+ @apply grid gap-1;
+}
+
+.side-group-trigger {
+ @apply flex w-full cursor-pointer items-center gap-2.5 rounded-xl border border-transparent px-3 py-2.5 text-left text-sm font-semibold text-muted-strong transition;
+ background: transparent;
+}
+
+.side-group-trigger:hover {
+ background: #fff;
+ border-color: rgba(128, 152, 192, 0.18);
+ color: var(--text);
+ box-shadow: 0 10px 18px rgba(15, 23, 42, 0.04);
+}
+
+.side-group-trigger.active {
+ color: var(--primary-strong);
+}
+
+.side-group-trigger span {
+ @apply min-w-0 flex-1 truncate;
+}
+
+.side-group-chevron {
+ @apply shrink-0;
+ transition: transform 190ms var(--ease-out-soft);
+}
+
+.side-nav-group.open .side-group-chevron {
+ transform: rotate(180deg);
+}
+
+.side-subnav {
+ display: grid;
+ grid-template-rows: 0fr;
+ opacity: 0;
+ transform: translateY(-4px);
+ transition:
+ grid-template-rows 220ms var(--ease-smooth),
+ opacity 170ms var(--ease-smooth),
+ transform 220ms var(--ease-out-soft);
+}
+
+.side-subnav.open {
+ grid-template-rows: 1fr;
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.side-subnav-inner {
+ @apply grid gap-1 overflow-hidden pl-[38px] pr-1;
+}
+
+.side-sub-link {
+ @apply block rounded-lg border border-transparent px-3 py-2 text-sm font-semibold text-muted no-underline transition;
+}
+
+.side-sub-link:hover {
+ background: rgba(255, 255, 255, 0.78);
+ color: var(--text);
+}
+
+.side-sub-link.active {
+ background: rgba(37, 99, 235, 0.10);
+ border-color: rgba(37, 99, 235, 0.18);
+ color: var(--primary-strong);
+}
+
.side-link:hover {
background: #fff;
border-color: rgba(128, 152, 192, 0.18);