@memberjunction/ng-explorer-settings 5.22.0 → 5.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/application-management/application-dialog/application-dialog.component.js +5 -4
- package/dist/lib/application-management/application-dialog/application-dialog.component.js.map +1 -1
- package/dist/lib/application-management/application-management.component.js +9 -8
- package/dist/lib/application-management/application-management.component.js.map +1 -1
- package/dist/lib/application-settings/application-settings.component.js +4 -3
- package/dist/lib/application-settings/application-settings.component.js.map +1 -1
- package/dist/lib/entity-permissions/entity-permissions.component.js +11 -10
- package/dist/lib/entity-permissions/entity-permissions.component.js.map +1 -1
- package/dist/lib/module.d.ts +2 -2
- package/dist/lib/module.js +4 -5
- package/dist/lib/module.js.map +1 -1
- package/dist/lib/role-management/role-management.component.js +9 -8
- package/dist/lib/role-management/role-management.component.js.map +1 -1
- package/dist/lib/sql-logging/sql-logging.component.js +4 -3
- package/dist/lib/sql-logging/sql-logging.component.js.map +1 -1
- package/dist/lib/user-app-config/user-app-config.component.js +4 -3
- package/dist/lib/user-app-config/user-app-config.component.js.map +1 -1
- package/dist/lib/user-management/user-management.component.js +11 -11
- package/dist/lib/user-management/user-management.component.js.map +1 -1
- package/dist/lib/user-profile-settings/user-profile-settings.component.js +4 -3
- package/dist/lib/user-profile-settings/user-profile-settings.component.js.map +1 -1
- package/package.json +18 -25
|
@@ -13,7 +13,8 @@ import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
|
13
13
|
import * as i0 from "@angular/core";
|
|
14
14
|
import * as i1 from "@angular/forms";
|
|
15
15
|
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
16
|
-
import * as i3 from "
|
|
16
|
+
import * as i3 from "@memberjunction/ng-ui-components";
|
|
17
|
+
import * as i4 from "./permission-dialog/permission-dialog.component";
|
|
17
18
|
const _forTrack0 = ($index, $item) => $item.ID;
|
|
18
19
|
const _forTrack1 = ($index, $item) => $item.entity.ID;
|
|
19
20
|
function EntityPermissionsComponent_For_74_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -681,7 +682,7 @@ let EntityPermissionsComponent = class EntityPermissionsComponent extends BaseDa
|
|
|
681
682
|
this.viewMode = mode;
|
|
682
683
|
}
|
|
683
684
|
static ɵfac = function EntityPermissionsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EntityPermissionsComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.NgZone)); };
|
|
684
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityPermissionsComponent, selectors: [["mj-entity-permissions"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 81, vars:
|
|
685
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityPermissionsComponent, selectors: [["mj-entity-permissions"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 81, vars: 28, consts: [[1, "entity-permissions-container"], [1, "sticky-header"], ["role", "toolbar", "aria-label", "Entity permissions actions", 1, "action-buttons"], [1, "mj-view-toggle"], ["mjButton", "", "role", "button", "tabindex", "0", "title", "List View", 3, "click", "keydown.enter", "keydown.space", "variant"], ["aria-hidden", "true", 1, "fa-solid", "fa-list"], ["mjButton", "", "role", "button", "tabindex", "0", "title", "Grid View", 3, "click", "keydown.enter", "keydown.space", "variant"], ["aria-hidden", "true", 1, "fa-solid", "fa-th"], ["mjButton", "", "variant", "secondary", "aria-label", "Refresh entity permissions data", "title", "Refresh", 1, "mj-btn-icon-mobile", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-refresh"], [1, "btn-text"], ["role", "region", "aria-label", "Permission statistics", 1, "mj-grid-4"], ["role", "article", "aria-label", "Total entities statistic", 1, "mj-card"], ["aria-hidden", "true", 1, "stat-icon", "stat-icon-total"], [1, "fa-solid", "fa-database"], [1, "stat-content"], ["aria-label", "Total entities count", 1, "stat-value"], [1, "stat-label"], ["role", "article", "aria-label", "Public entities statistic", 1, "mj-card"], ["aria-hidden", "true", 1, "stat-icon", "stat-icon-public"], [1, "fa-solid", "fa-globe"], ["aria-label", "Public entities count", 1, "stat-value"], ["role", "article", "aria-label", "Restricted entities statistic", 1, "mj-card"], ["aria-hidden", "true", 1, "stat-icon", "stat-icon-restricted"], [1, "fa-solid", "fa-lock"], ["aria-label", "Restricted entities count", 1, "stat-value"], ["role", "article", "aria-label", "Total permissions statistic", 1, "mj-card"], ["aria-hidden", "true", 1, "stat-icon", "stat-icon-permissions"], [1, "fa-solid", "fa-key"], ["aria-label", "Total permissions count", 1, "stat-value"], ["role", "search", "aria-label", "Entity filters", 1, "filters-section"], [1, "filters-row"], [1, "mobile-search-container"], [1, "mj-search"], ["aria-hidden", "true", 1, "fa-solid", "fa-search", "mj-search-icon"], ["type", "text", "placeholder", "Search entities by name or description...", "aria-label", "Search entities", 1, "mj-search-input", 3, "input", "value"], ["aria-label", "Open filters", 1, "filter-button", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-filter"], [1, "mj-filter-group"], ["id", "access-level-label", 1, "mj-filter-label"], ["role", "group", "aria-labelledby", "access-level-label", 1, "mj-filter-buttons"], ["mjButton", "", "aria-label", "Show all access levels", 3, "click", "variant"], ["mjButton", "", "aria-label", "Show only public entities", 3, "click", "variant"], ["mjButton", "", "aria-label", "Show only restricted entities", 3, "click", "variant"], ["mjButton", "", "aria-label", "Show only custom access entities", 3, "click", "variant"], ["for", "role-filter", 1, "mj-filter-label"], ["id", "role-filter", "aria-label", "Filter entities by role", 1, "mj-filter-select", 3, "change"], ["value", ""], [3, "value"], [1, "scrollable-content"], ["role", "status", "aria-live", "polite", "aria-busy", "true", 1, "loading-container"], ["role", "alert", "aria-live", "assertive", 1, "error-container"], [1, "content-area"], [3, "result", "visible", "data"], ["role", "presentation", 1, "filter-modal-backdrop"], ["text", "Loading entity permissions...", "size", "medium"], [1, "error-content"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle", "error-icon"], [1, "error-message"], ["mjButton", "", "variant", "primary", "aria-label", "Retry loading entity permissions", 3, "click"], ["role", "list", "aria-label", "Entity permissions list", 1, "entities-list"], ["role", "list", "aria-label", "Entity permissions grid", 1, "entities-grid"], ["role", "status", 1, "empty-state"], ["role", "listitem", 1, "entity-card", 3, "expanded"], ["role", "listitem", 1, "entity-card"], ["tabindex", "0", "role", "button", 1, "entity-header", 3, "click", "keydown.enter", "keydown.space"], [1, "entity-info"], ["aria-hidden", "true", 1, "entity-icon-wrapper"], [1, "fa-solid", "fa-table"], [1, "entity-details"], [1, "entity-name"], [1, "entity-description"], [1, "entity-meta"], [1, "access-badge"], ["aria-hidden", "true"], [1, "entity-actions", 3, "click"], ["mjButton", "", "variant", "flat", "size", "sm", "title", "Edit Permissions", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-edit"], [1, "expand-btn"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down"], ["role", "region", 1, "entity-content"], [1, "mobile-actions-bar", 3, "click"], [1, "mobile-action-buttons"], [1, "btn-label"], ["role", "table", "aria-label", "Role permissions", 1, "permissions-grid"], [1, "no-permissions"], ["role", "rowgroup", 1, "permissions-header"], ["role", "row"], ["scope", "col", "role", "columnheader", 1, "role-header"], ["scope", "col", "role", "columnheader", 1, "permission-header"], ["role", "rowgroup"], ["role", "row", 1, "permission-row"], ["role", "cell", 1, "role-name"], ["role", "cell", 1, "permission-cell"], [1, "entity-grid-card", 3, "class"], [1, "entity-grid-card"], [1, "grid-card-header"], ["aria-hidden", "true", 1, "fa-solid", "fa-table"], [1, "grid-card-title"], [1, "grid-card-description"], [1, "grid-card-footer"], [1, "access-label"], [1, "permission-count"], ["aria-hidden", "true", 1, "fa-solid", "fa-shield-alt", "empty-state-icon"], [1, "empty-text"], [1, "empty-subtext"], ["mjButton", "", "variant", "primary", "aria-label", "Refresh permissions data", 3, "click"], ["role", "presentation", 1, "filter-modal-backdrop", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "filter-modal-title", 1, "filter-modal", 3, "click"], [1, "filter-modal-header"], ["id", "filter-modal-title", 1, "filter-modal-title"], ["aria-label", "Close filters", 1, "filter-modal-close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-times"], [1, "filter-modal-body"], [1, "filter-options-container"], [1, "filter-group"], [1, "filter-group-label"], [1, "filter-group-options"], [1, "filter-option"], ["type", "radio", "name", "accessLevel", "value", "all", 3, "change", "checked"], [1, "filter-option-label"], ["type", "radio", "name", "accessLevel", "value", "public", 3, "change", "checked"], ["type", "radio", "name", "accessLevel", "value", "restricted", 3, "change", "checked"], ["type", "radio", "name", "accessLevel", "value", "custom", 3, "change", "checked"], ["type", "radio", "name", "role", "value", "", 3, "change", "checked"], [1, "filter-option", 3, "selected"], [1, "filter-modal-footer"], ["mjButton", "", "variant", "primary", 3, "click"], ["mjButton", "", 3, "click"], ["type", "radio", "name", "role", 3, "change", "value", "checked"]], template: function EntityPermissionsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
685
686
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div", 3)(4, "button", 4);
|
|
686
687
|
i0.ɵɵlistener("click", function EntityPermissionsComponent_Template_button_click_4_listener() { return ctx.setViewMode("list"); })("keydown.enter", function EntityPermissionsComponent_Template_button_keydown_enter_4_listener() { return ctx.setViewMode("list"); })("keydown.space", function EntityPermissionsComponent_Template_button_keydown_space_4_listener($event) { ctx.setViewMode("list"); return $event.preventDefault(); });
|
|
687
688
|
i0.ɵɵelement(5, "i", 5);
|
|
@@ -784,10 +785,10 @@ let EntityPermissionsComponent = class EntityPermissionsComponent extends BaseDa
|
|
|
784
785
|
i0.ɵɵelementEnd();
|
|
785
786
|
} if (rf & 2) {
|
|
786
787
|
i0.ɵɵadvance(4);
|
|
787
|
-
i0.ɵɵ
|
|
788
|
+
i0.ɵɵproperty("variant", ctx.viewMode === "list" ? "primary" : "flat");
|
|
788
789
|
i0.ɵɵattribute("aria-label", "List view" + (ctx.viewMode === "list" ? " (active)" : ""))("aria-pressed", ctx.viewMode === "list");
|
|
789
790
|
i0.ɵɵadvance(2);
|
|
790
|
-
i0.ɵɵ
|
|
791
|
+
i0.ɵɵproperty("variant", ctx.viewMode === "grid" ? "primary" : "flat");
|
|
791
792
|
i0.ɵɵattribute("aria-label", "Grid view" + (ctx.viewMode === "grid" ? " (active)" : ""))("aria-pressed", ctx.viewMode === "grid");
|
|
792
793
|
i0.ɵɵadvance(2);
|
|
793
794
|
i0.ɵɵproperty("disabled", ctx.isLoading);
|
|
@@ -804,16 +805,16 @@ let EntityPermissionsComponent = class EntityPermissionsComponent extends BaseDa
|
|
|
804
805
|
i0.ɵɵadvance(8);
|
|
805
806
|
i0.ɵɵproperty("value", ctx.filters$.value.entitySearch);
|
|
806
807
|
i0.ɵɵadvance(9);
|
|
807
|
-
i0.ɵɵ
|
|
808
|
+
i0.ɵɵproperty("variant", ctx.filters$.value.accessLevel === "all" ? "primary" : "flat");
|
|
808
809
|
i0.ɵɵattribute("aria-pressed", ctx.filters$.value.accessLevel === "all");
|
|
809
810
|
i0.ɵɵadvance(2);
|
|
810
|
-
i0.ɵɵ
|
|
811
|
+
i0.ɵɵproperty("variant", ctx.filters$.value.accessLevel === "public" ? "primary" : "flat");
|
|
811
812
|
i0.ɵɵattribute("aria-pressed", ctx.filters$.value.accessLevel === "public");
|
|
812
813
|
i0.ɵɵadvance(2);
|
|
813
|
-
i0.ɵɵ
|
|
814
|
+
i0.ɵɵproperty("variant", ctx.filters$.value.accessLevel === "restricted" ? "primary" : "flat");
|
|
814
815
|
i0.ɵɵattribute("aria-pressed", ctx.filters$.value.accessLevel === "restricted");
|
|
815
816
|
i0.ɵɵadvance(2);
|
|
816
|
-
i0.ɵɵ
|
|
817
|
+
i0.ɵɵproperty("variant", ctx.filters$.value.accessLevel === "custom" ? "primary" : "flat");
|
|
817
818
|
i0.ɵɵattribute("aria-pressed", ctx.filters$.value.accessLevel === "custom");
|
|
818
819
|
i0.ɵɵadvance(8);
|
|
819
820
|
i0.ɵɵrepeater(ctx.roles);
|
|
@@ -827,7 +828,7 @@ let EntityPermissionsComponent = class EntityPermissionsComponent extends BaseDa
|
|
|
827
828
|
i0.ɵɵproperty("visible", ctx.showPermissionDialog)("data", ctx.permissionDialogData);
|
|
828
829
|
i0.ɵɵadvance();
|
|
829
830
|
i0.ɵɵconditional(ctx.showMobileFilters ? 80 : -1);
|
|
830
|
-
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i2.LoadingComponent, i3.PermissionDialogComponent], styles: ["\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n\n.sticky-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n\n\n\n\n.scrollable-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem 2.5rem;\n }\n}\n\n\n\n\n\n.action-buttons[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons[_ngcontent-%COMP%] {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.5rem 0.75rem;\n min-height: 40px;\n gap: 0;\n border-radius: var(--mj-radius-full);\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n}\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n.mj-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}\n\n\n\n\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n\n\n\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2rem;\n }\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n }\n}\n\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section[_ngcontent-%COMP%] {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row[_ngcontent-%COMP%] {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n border-radius: var(--mj-radius-full);\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn-primary[_ngcontent-%COMP%] {\n background-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n\n\n.mj-search[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search[_ngcontent-%COMP%]:focus-within .mj-search-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n\n\n\n\n.error-container[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-icon[_ngcontent-%COMP%] {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-message[_ngcontent-%COMP%] {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n\n\n\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog[_ngcontent-%COMP%] {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n\n .modal-body[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-footer[_ngcontent-%COMP%] {\n padding: 1rem;\n flex-direction: column;\n }\n\n .modal-footer[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n }\n}\n\n\n\n\n\n.mj-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n min-height: 44px;\n}\n\n.mj-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n\n\n.mj-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-primary[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n\n\n.mj-btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n}\n\n.mj-btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-btn-secondary[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n border-color: var(--mj-color-brand-700);\n}\n\n\n\n.mj-btn-ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n\n.mj-btn-ghost[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-btn-ghost[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n}\n\n\n\n.mj-btn-danger[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-color-error-300);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-danger[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-error-200);\n transform: scale(0.98);\n}\n\n\n\n.mj-btn-sm[_ngcontent-%COMP%] {\n padding: 0.5rem 0.875rem;\n font-size: 0.8125rem;\n min-height: 36px;\n}\n\n\n\n.mj-btn-icon-only[_ngcontent-%COMP%] {\n padding: 0.625rem;\n min-width: 44px;\n min-height: 44px;\n}\n\n\n\n.mj-btn-icon-mobile[_ngcontent-%COMP%] {\n gap: 0.5rem;\n}\n\n.mj-btn-icon-mobile[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: inline;\n}\n\n\n\n.mj-btn-ghost.mj-btn-danger[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-status-error);\n box-shadow: none;\n}\n\n.mj-btn-ghost.mj-btn-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n\n\n\n\n.filter-button[_ngcontent-%COMP%] {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n\n\n\n\n\n.filter-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n}\n\n\n\n.filter-options-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%], \n.filter-option[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] .filter-option-label[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n\n\n.text-danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.text-warning[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n}\n\n.text-success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n\n\n\n\n.mj-search-input[_ngcontent-%COMP%]:focus-visible, \nbutton[_ngcontent-%COMP%]:focus-visible, \n.mj-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n\n\n@media (prefers-reduced-motion: reduce) {\n *[_ngcontent-%COMP%], \n *[_ngcontent-%COMP%]::before, \n *[_ngcontent-%COMP%]::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}", "\n\n\n\n\n\n\n\n\n\n.entity-permissions-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n position: relative;\n margin: 0 auto;\n width: 100%;\n background: var(--mj-bg-page);\n}\n\n\n\n\n\n.sticky-header[_ngcontent-%COMP%] {\n padding: 1rem;\n}\n\n@media (min-width: 640px) {\n .sticky-header[_ngcontent-%COMP%] {\n padding: 1.25rem;\n }\n}\n\n@media (min-width: 768px) {\n .sticky-header[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .sticky-header[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n\n\n\n\n@media (min-width: 640px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.25rem;\n }\n}\n\n@media (min-width: 768px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n\n\n\n\n.mj-btn[_ngcontent-%COMP%] {\n min-width: 44px;\n text-decoration: none;\n}\n\n\n\n.mj-btn-ghost[_ngcontent-%COMP%] {\n padding: 0.75rem 1rem;\n}\n\n\n\n.mj-btn-sm[_ngcontent-%COMP%] {\n min-width: 36px;\n}\n\n\n\n.mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.75rem 1.5rem;\n}\n\n@media (min-width: 640px) {\n .mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.75rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .mj-btn-icon-mobile[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.625rem;\n gap: 0;\n }\n}\n\n\n\n\n\n.action-buttons[_ngcontent-%COMP%] {\n justify-content: space-between;\n margin-bottom: 1rem;\n flex-wrap: wrap;\n align-items: center;\n padding: 0;\n background: transparent;\n}\n\n@media (min-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n margin-bottom: 1.25rem;\n }\n}\n\n\n\n\n\n@media (max-width: 639px) {\n .sticky-header[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n }\n\n .action-buttons[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n margin-bottom: 0;\n order: 1;\n width: 100%;\n }\n\n .mj-view-toggle[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n padding: 3px;\n gap: 2px;\n }\n\n .mj-view-toggle[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n padding: 0.5rem 0.625rem;\n min-width: 36px;\n min-height: 36px;\n border-radius: var(--mj-radius-md);\n }\n\n .mj-view-toggle[_ngcontent-%COMP%] .mj-btn.mj-btn-primary[_ngcontent-%COMP%] {\n box-shadow: none;\n }\n\n .action-buttons[_ngcontent-%COMP%] > .mj-btn-secondary[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 0.5rem 0.625rem;\n min-width: 36px;\n min-height: 36px;\n border-radius: var(--mj-radius-lg);\n }\n\n .filters-section[_ngcontent-%COMP%] {\n order: 2;\n width: 100%;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 0.75rem;\n margin-bottom: 0.5rem;\n border-radius: var(--mj-radius-lg);\n }\n\n .filters-row[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 0.5rem;\n flex-wrap: nowrap;\n }\n\n \n\n .mobile-search-container[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n flex: 1;\n min-width: 0;\n }\n\n .mj-search[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 0.75rem 1rem 0.75rem 2.5rem;\n min-height: 44px;\n font-size: 1rem;\n border-width: 1.5px;\n border-radius: var(--mj-radius-full);\n box-sizing: border-box;\n width: 100%;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 0.875rem;\n font-size: 1rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]::placeholder {\n font-size: 0.875rem;\n }\n\n \n\n .mj-filter-group[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mj-filter-label[_ngcontent-%COMP%] {\n display: none;\n }\n\n .mj-filter-select[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n.mj-view-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-view-toggle[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n border-radius: var(--mj-radius-full);\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n font-size: 0.875rem;\n font-weight: 500;\n}\n\n.mj-view-toggle[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%]:hover:not(:disabled):not(.mj-btn-primary) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-view-toggle[_ngcontent-%COMP%] .mj-btn.mj-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n margin-bottom: 1rem;\n width: 100%;\n padding: 0;\n background: transparent;\n}\n\n@media (max-width: 639px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n display: none !important;\n }\n}\n\n@media (min-width: 640px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1.25rem;\n margin-bottom: 1.25rem;\n }\n}\n\n\n\n.mj-card[_ngcontent-%COMP%] {\n min-width: 0;\n box-shadow: none;\n}\n\n\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.875rem;\n }\n}\n\n\n\n.stat-icon-public[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n.stat-icon-restricted[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-permissions[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n border-radius: var(--mj-radius-xl);\n padding: 1rem;\n margin-bottom: 0;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n@media (min-width: 768px) {\n .filters-section[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .filters-section[_ngcontent-%COMP%] {\n padding: 1.25rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .filters-row[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .filters-row[_ngcontent-%COMP%] {\n gap: 1.5rem;\n }\n}\n\n\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.125rem;\n font-size: 1.125rem;\n }\n}\n\n\n\n.mj-filter-buttons[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 500;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%]:hover:not(:disabled):not(.mj-btn-primary) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn.mj-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n@media (max-width: 639px) {\n .mj-filter-buttons[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n }\n\n .mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n flex: 1;\n min-width: calc(50% - 4px);\n padding: 0.5rem 0.75rem;\n font-size: 0.75rem;\n }\n}\n\n\n\n.mj-filter-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n line-height: 1.2;\n}\n\n\n\n.mj-filter-select[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 500;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n height: 44px;\n min-width: 150px;\n box-sizing: border-box;\n}\n\n.mj-filter-select[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-filter-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n@media (max-width: 639px) {\n .mj-filter-select[_ngcontent-%COMP%] {\n width: 100%;\n }\n}\n\n\n\n.mobile-search-container[_ngcontent-%COMP%] {\n display: contents;\n}\n\n\n\n.filter-button[_ngcontent-%COMP%] .filter-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -4px;\n right: -4px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.625rem;\n font-weight: 700;\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n}\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n min-height: 200px;\n padding: 3rem 1.5rem;\n flex-direction: row;\n}\n\n\n\n\n\n.content-area[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-md);\n padding: 1.25rem;\n}\n\n@media (min-width: 1024px) {\n .content-area[_ngcontent-%COMP%] {\n padding: 1.75rem;\n }\n}\n\n\n\n\n\n.entities-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n overflow: visible;\n}\n\n@media (min-width: 768px) {\n .entities-list[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n\n\n.entity-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-card.expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-card.expanded[_ngcontent-%COMP%] .expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n.entity-header[_ngcontent-%COMP%] {\n padding: 1rem;\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n gap: 0.75rem;\n}\n\n.entity-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .entity-header[_ngcontent-%COMP%] {\n padding: 1.25rem 1.5rem;\n }\n}\n\n\n\n.entity-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n@media (min-width: 768px) {\n .entity-info[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n.entity-icon-wrapper[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n background: var(--mj-color-accent-300);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-brand-primary);\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .entity-icon-wrapper[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n\n\n.entity-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.entity-details[_ngcontent-%COMP%] .entity-name[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.25rem 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .entity-details[_ngcontent-%COMP%] .entity-name[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n}\n\n.entity-details[_ngcontent-%COMP%] .entity-description[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .entity-details[_ngcontent-%COMP%] .entity-description[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n}\n\n\n\n.entity-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .entity-meta[_ngcontent-%COMP%] {\n gap: 0.75rem;\n }\n}\n\n\n\n\n\n.access-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .access-badge[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n font-size: 0.8125rem;\n }\n}\n\n.access-badge.access-public[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.access-badge.access-restricted[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.access-badge.access-custom[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n\n\n.entity-actions[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 640px) {\n .entity-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n@media (max-width: 639px) {\n .entity-meta[_ngcontent-%COMP%] > .access-badge[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n\n\n\n\n.entity-content[_ngcontent-%COMP%] {\n padding: 1.25rem;\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n animation: _ngcontent-%COMP%_slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@media (min-width: 768px) {\n .entity-content[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .entity-content[_ngcontent-%COMP%] {\n padding: 1.75rem;\n }\n}\n\n\n\n\n\n@media (max-width: 639px) {\n .mobile-actions-bar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.75rem;\n margin: -1.25rem -1.25rem 1rem -1.25rem;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .mobile-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n }\n\n .mobile-action-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n }\n\n .mobile-action-buttons[_ngcontent-%COMP%] .btn-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n }\n}\n\n\n\n\n\n.permissions-grid[_ngcontent-%COMP%] {\n width: 100%;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n border-collapse: collapse;\n}\n\n\n\n.permissions-header[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr 1fr;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n@media (min-width: 768px) {\n .permissions-header[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n gap: 0.75rem;\n }\n}\n\n@media (max-width: 639px) {\n .permissions-header[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] {\n grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;\n padding: 0.625rem 0.75rem;\n font-size: 0.75rem;\n }\n}\n\n\n\n.permission-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr 1fr;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n transition: background-color 0.2s ease;\n}\n\n.permission-row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface);\n}\n\n.permission-row[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n@media (min-width: 768px) {\n .permission-row[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n gap: 0.75rem;\n }\n}\n\n@media (max-width: 639px) {\n .permission-row[_ngcontent-%COMP%] {\n grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;\n padding: 0.625rem 0.75rem;\n }\n}\n\n.role-header[_ngcontent-%COMP%], \n.permission-header[_ngcontent-%COMP%] {\n text-align: left;\n}\n\n.permission-header[_ngcontent-%COMP%] {\n text-align: center;\n}\n\n.role-name[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--mj-text-primary);\n font-size: 0.875rem;\n display: flex;\n align-items: center;\n}\n\n@media (max-width: 639px) {\n .role-name[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n }\n}\n\n.permission-cell[_ngcontent-%COMP%] {\n text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n\n.text-success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.text-muted[_ngcontent-%COMP%] {\n color: var(--mj-color-neutral-400);\n opacity: 0.6;\n}\n\n.no-permissions[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 0.875rem;\n margin: 0;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n text-align: center;\n}\n\n\n\n\n\n.entities-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 0.75rem;\n grid-template-columns: 1fr;\n}\n\n@media (min-width: 640px) {\n .entities-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .entities-grid[_ngcontent-%COMP%] {\n gap: 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .entities-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(3, 1fr);\n gap: 1.5rem;\n }\n}\n\n\n\n.entity-grid-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n padding: 1.25rem;\n position: relative;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-grid-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-grid-card.access-public[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.entity-grid-card.access-restricted[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.entity-grid-card.access-custom[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-color-warning-500);\n}\n\n@media (min-width: 768px) {\n .entity-grid-card[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n\n\n.grid-card-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 0.75rem;\n font-size: 1.5rem;\n color: var(--mj-brand-primary);\n}\n\n@media (min-width: 768px) {\n .grid-card-header[_ngcontent-%COMP%] {\n margin-bottom: 1rem;\n }\n}\n\n\n\n.grid-card-title[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n@media (min-width: 768px) {\n .grid-card-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n}\n\n\n\n.grid-card-description[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0 0 0.75rem 0;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n@media (min-width: 768px) {\n .grid-card-description[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n margin: 0 0 1rem 0;\n }\n}\n\n\n\n.grid-card-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n}\n\n\n\n.access-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n font-weight: 500;\n}\n\n.permission-count[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n@media (min-width: 768px) {\n .empty-state[_ngcontent-%COMP%] {\n padding: 5rem 2.5rem;\n }\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-state-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n\n\n.error-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n}\n\n@media (min-width: 768px) {\n .error-container[_ngcontent-%COMP%] {\n padding: 5rem 2.5rem;\n }\n}\n\n.error-container[_ngcontent-%COMP%] .error-icon[_ngcontent-%COMP%] {\n margin-bottom: 0.5rem;\n}\n\n\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 800px;\n }\n}\n\n\n\n\n\n@media (max-width: 374px) {\n .filters-section[_ngcontent-%COMP%] {\n padding: 0.5rem;\n margin-bottom: 0.375rem;\n }\n\n .filters-row[_ngcontent-%COMP%] {\n gap: 0.375rem;\n }\n\n .mobile-search-container[_ngcontent-%COMP%] {\n gap: 0.375rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 0.625rem 0.75rem 0.625rem 2.25rem;\n font-size: 0.875rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 0.75rem;\n font-size: 0.875rem;\n }\n\n .filter-button[_ngcontent-%COMP%] {\n padding: 0.625rem;\n min-width: 40px;\n flex-shrink: 0;\n }\n\n .filter-button[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: none;\n }\n\n .filter-modal-header[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n\n .filter-modal-body[_ngcontent-%COMP%] {\n padding: 1.25rem;\n }\n\n .filter-modal-footer[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}"] });
|
|
831
|
+
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i2.LoadingComponent, i3.MJButtonDirective, i4.PermissionDialogComponent], styles: ["\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n\n.sticky-header[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n\n\n\n\n.scrollable-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 2rem 2.5rem;\n }\n}\n\n\n\n\n\n.action-buttons[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons[_ngcontent-%COMP%] {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.5rem 0.75rem;\n min-height: 40px;\n gap: 0;\n border-radius: var(--mj-radius-full);\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n}\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n.mj-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}\n\n\n\n\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n\n\n\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2rem;\n }\n}\n\n.stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n }\n}\n\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section[_ngcontent-%COMP%] {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row[_ngcontent-%COMP%] {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n border-radius: var(--mj-radius-full);\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn-primary[_ngcontent-%COMP%] {\n background-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n\n\n.mj-search[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search[_ngcontent-%COMP%]:focus-within .mj-search-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.625rem;\n}\n\n\n\n\n\n.mobile-actions-bar[_ngcontent-%COMP%] {\n display: none;\n}\n\n.mobile-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n\n\n\n\n.error-container[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-icon[_ngcontent-%COMP%] {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container[_ngcontent-%COMP%] .error-message[_ngcontent-%COMP%] {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n\n\n\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body[_ngcontent-%COMP%] p[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog[_ngcontent-%COMP%] {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n\n .modal-body[_ngcontent-%COMP%] {\n padding: 1rem;\n }\n\n .modal-footer[_ngcontent-%COMP%] {\n padding: 1rem;\n flex-direction: column;\n }\n\n .modal-footer[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: center;\n }\n}\n\n\n\n\n\n.mj-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n min-height: 44px;\n}\n\n.mj-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n\n\n.mj-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-primary[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n\n\n.mj-btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n}\n\n.mj-btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-btn-secondary[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n border-color: var(--mj-color-brand-700);\n}\n\n\n\n.mj-btn-ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n\n.mj-btn-ghost[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-btn-ghost[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n}\n\n\n\n.mj-btn-danger[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-color-error-300);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-danger[_ngcontent-%COMP%]:active:not(:disabled) {\n background: var(--mj-color-error-200);\n transform: scale(0.98);\n}\n\n\n\n.mj-btn-sm[_ngcontent-%COMP%] {\n padding: 0.5rem 0.875rem;\n font-size: 0.8125rem;\n min-height: 36px;\n}\n\n\n\n.mj-btn-icon-only[_ngcontent-%COMP%] {\n padding: 0.625rem;\n min-width: 44px;\n min-height: 44px;\n}\n\n\n\n.mj-btn-icon-mobile[_ngcontent-%COMP%] {\n gap: 0.5rem;\n}\n\n.mj-btn-icon-mobile[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: inline;\n}\n\n\n\n.mj-btn-ghost.mj-btn-danger[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-status-error);\n box-shadow: none;\n}\n\n.mj-btn-ghost.mj-btn-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n\n\n\n\n.filter-button[_ngcontent-%COMP%] {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1rem;\n}\n\n\n\n\n\n.filter-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close[_ngcontent-%COMP%] {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n}\n\n\n\n.filter-options-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%], \n.filter-option[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] .filter-option-label[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n\n\n.text-danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.text-warning[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-500);\n}\n\n.text-success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n\n\n\n\n.mj-search-input[_ngcontent-%COMP%]:focus-visible, \nbutton[_ngcontent-%COMP%]:focus-visible, \n.mj-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n\n\n\n\n@media (prefers-reduced-motion: reduce) {\n *[_ngcontent-%COMP%], \n *[_ngcontent-%COMP%]::before, \n *[_ngcontent-%COMP%]::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}", "\n\n\n\n\n\n\n\n\n\n.entity-permissions-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n position: relative;\n margin: 0 auto;\n width: 100%;\n background: var(--mj-bg-page);\n}\n\n\n\n\n\n.sticky-header[_ngcontent-%COMP%] {\n padding: 1rem;\n}\n\n@media (min-width: 640px) {\n .sticky-header[_ngcontent-%COMP%] {\n padding: 1.25rem;\n }\n}\n\n@media (min-width: 768px) {\n .sticky-header[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .sticky-header[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n\n\n\n\n@media (min-width: 640px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.25rem;\n }\n}\n\n@media (min-width: 768px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content[_ngcontent-%COMP%] {\n padding: 1.5rem 2rem;\n }\n}\n\n\n\n\n\n.mj-btn[_ngcontent-%COMP%] {\n min-width: 44px;\n text-decoration: none;\n}\n\n\n\n.mj-btn-ghost[_ngcontent-%COMP%] {\n padding: 0.75rem 1rem;\n}\n\n\n\n.mj-btn-sm[_ngcontent-%COMP%] {\n min-width: 36px;\n}\n\n\n\n.mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.75rem 1.5rem;\n}\n\n@media (min-width: 640px) {\n .mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.75rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .mj-btn-icon-mobile[_ngcontent-%COMP%] .btn-text[_ngcontent-%COMP%] {\n display: none;\n }\n\n .mj-btn-icon-mobile[_ngcontent-%COMP%] {\n padding: 0.625rem;\n gap: 0;\n }\n}\n\n\n\n\n\n.action-buttons[_ngcontent-%COMP%] {\n justify-content: space-between;\n margin-bottom: 1rem;\n flex-wrap: wrap;\n align-items: center;\n padding: 0;\n background: transparent;\n}\n\n@media (min-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n margin-bottom: 1.25rem;\n }\n}\n\n\n\n\n\n@media (max-width: 639px) {\n .sticky-header[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n }\n\n .action-buttons[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n margin-bottom: 0;\n order: 1;\n width: 100%;\n }\n\n .mj-view-toggle[_ngcontent-%COMP%] {\n flex-shrink: 0;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n padding: 3px;\n gap: 2px;\n }\n\n .mj-view-toggle[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n padding: 0.5rem 0.625rem;\n min-width: 36px;\n min-height: 36px;\n border-radius: var(--mj-radius-md);\n }\n\n .mj-view-toggle[_ngcontent-%COMP%] .mj-btn.mj-btn-primary[_ngcontent-%COMP%] {\n box-shadow: none;\n }\n\n .action-buttons[_ngcontent-%COMP%] > .mj-btn-secondary[_ngcontent-%COMP%] {\n flex-shrink: 0;\n padding: 0.5rem 0.625rem;\n min-width: 36px;\n min-height: 36px;\n border-radius: var(--mj-radius-lg);\n }\n\n .filters-section[_ngcontent-%COMP%] {\n order: 2;\n width: 100%;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 0.75rem;\n margin-bottom: 0.5rem;\n border-radius: var(--mj-radius-lg);\n }\n\n .filters-row[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 0.5rem;\n flex-wrap: nowrap;\n }\n\n \n\n .mobile-search-container[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n flex: 1;\n min-width: 0;\n }\n\n .mj-search[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 0.75rem 1rem 0.75rem 2.5rem;\n min-height: 44px;\n font-size: 1rem;\n border-width: 1.5px;\n border-radius: var(--mj-radius-full);\n box-sizing: border-box;\n width: 100%;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 0.875rem;\n font-size: 1rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%]::placeholder {\n font-size: 0.875rem;\n }\n\n \n\n .mj-filter-group[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mj-filter-label[_ngcontent-%COMP%] {\n display: none;\n }\n\n .mj-filter-select[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n.mj-view-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-view-toggle[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n border-radius: var(--mj-radius-full);\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n font-size: 0.875rem;\n font-weight: 500;\n}\n\n.mj-view-toggle[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%]:hover:not(:disabled):not(.mj-btn-primary) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-view-toggle[_ngcontent-%COMP%] .mj-btn.mj-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n\n\n.mj-grid-4[_ngcontent-%COMP%] {\n margin-bottom: 1rem;\n width: 100%;\n padding: 0;\n background: transparent;\n}\n\n@media (max-width: 639px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n display: none !important;\n }\n}\n\n@media (min-width: 640px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .mj-grid-4[_ngcontent-%COMP%] {\n gap: 1.25rem;\n margin-bottom: 1.25rem;\n }\n}\n\n\n\n.mj-card[_ngcontent-%COMP%] {\n min-width: 0;\n box-shadow: none;\n}\n\n\n\n@media (min-width: 768px) {\n .stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 1.875rem;\n }\n}\n\n\n\n.stat-icon-public[_ngcontent-%COMP%] {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n.stat-icon-restricted[_ngcontent-%COMP%] {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-permissions[_ngcontent-%COMP%] {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n\n\n\n\n.filters-section[_ngcontent-%COMP%] {\n border-radius: var(--mj-radius-xl);\n padding: 1rem;\n margin-bottom: 0;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n@media (min-width: 768px) {\n .filters-section[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .filters-section[_ngcontent-%COMP%] {\n padding: 1.25rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .filters-row[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .filters-row[_ngcontent-%COMP%] {\n gap: 1.5rem;\n }\n}\n\n\n\n@media (min-width: 1024px) {\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem 1rem 3rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 1.125rem;\n font-size: 1.125rem;\n }\n}\n\n\n\n.mj-filter-buttons[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 500;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%]:hover:not(:disabled):not(.mj-btn-primary) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-filter-buttons[_ngcontent-%COMP%] .mj-btn.mj-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n@media (max-width: 639px) {\n .mj-filter-buttons[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n }\n\n .mj-filter-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n flex: 1;\n min-width: calc(50% - 4px);\n padding: 0.5rem 0.75rem;\n font-size: 0.75rem;\n }\n}\n\n\n\n.mj-filter-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n line-height: 1.2;\n}\n\n\n\n.mj-filter-select[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 500;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n height: 44px;\n min-width: 150px;\n box-sizing: border-box;\n}\n\n.mj-filter-select[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-filter-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n@media (max-width: 639px) {\n .mj-filter-select[_ngcontent-%COMP%] {\n width: 100%;\n }\n}\n\n\n\n.mobile-search-container[_ngcontent-%COMP%] {\n display: contents;\n}\n\n\n\n.filter-button[_ngcontent-%COMP%] .filter-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -4px;\n right: -4px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.625rem;\n font-weight: 700;\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n}\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n min-height: 200px;\n padding: 3rem 1.5rem;\n flex-direction: row;\n}\n\n\n\n\n\n.content-area[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-md);\n padding: 1.25rem;\n}\n\n@media (min-width: 1024px) {\n .content-area[_ngcontent-%COMP%] {\n padding: 1.75rem;\n }\n}\n\n\n\n\n\n.entities-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n overflow: visible;\n}\n\n@media (min-width: 768px) {\n .entities-list[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n\n\n.entity-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-card.expanded[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-card.expanded[_ngcontent-%COMP%] .expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n.entity-header[_ngcontent-%COMP%] {\n padding: 1rem;\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n gap: 0.75rem;\n}\n\n.entity-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .entity-header[_ngcontent-%COMP%] {\n padding: 1.25rem 1.5rem;\n }\n}\n\n\n\n.entity-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n@media (min-width: 768px) {\n .entity-info[_ngcontent-%COMP%] {\n gap: 1rem;\n }\n}\n\n\n\n.entity-icon-wrapper[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n background: var(--mj-color-accent-300);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-brand-primary);\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .entity-icon-wrapper[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n\n\n.entity-details[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.entity-details[_ngcontent-%COMP%] .entity-name[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.25rem 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .entity-details[_ngcontent-%COMP%] .entity-name[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n}\n\n.entity-details[_ngcontent-%COMP%] .entity-description[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .entity-details[_ngcontent-%COMP%] .entity-description[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n }\n}\n\n\n\n.entity-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .entity-meta[_ngcontent-%COMP%] {\n gap: 0.75rem;\n }\n}\n\n\n\n\n\n.access-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .access-badge[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n font-size: 0.8125rem;\n }\n}\n\n.access-badge.access-public[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.access-badge.access-restricted[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.access-badge.access-custom[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n\n\n.entity-actions[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (min-width: 640px) {\n .entity-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n@media (max-width: 639px) {\n .entity-meta[_ngcontent-%COMP%] > .access-badge[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n.expand-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n\n\n\n\n.entity-content[_ngcontent-%COMP%] {\n padding: 1.25rem;\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n animation: _ngcontent-%COMP%_slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@media (min-width: 768px) {\n .entity-content[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .entity-content[_ngcontent-%COMP%] {\n padding: 1.75rem;\n }\n}\n\n\n\n\n\n@media (max-width: 639px) {\n .mobile-actions-bar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.75rem;\n margin: -1.25rem -1.25rem 1rem -1.25rem;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .mobile-action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n }\n\n .mobile-action-buttons[_ngcontent-%COMP%] .mj-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n }\n\n .mobile-action-buttons[_ngcontent-%COMP%] .btn-label[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n }\n}\n\n\n\n\n\n.permissions-grid[_ngcontent-%COMP%] {\n width: 100%;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n border-collapse: collapse;\n}\n\n\n\n.permissions-header[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr 1fr;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n@media (min-width: 768px) {\n .permissions-header[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n gap: 0.75rem;\n }\n}\n\n@media (max-width: 639px) {\n .permissions-header[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] {\n grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;\n padding: 0.625rem 0.75rem;\n font-size: 0.75rem;\n }\n}\n\n\n\n.permission-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr 1fr;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n transition: background-color 0.2s ease;\n}\n\n.permission-row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface);\n}\n\n.permission-row[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n@media (min-width: 768px) {\n .permission-row[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n gap: 0.75rem;\n }\n}\n\n@media (max-width: 639px) {\n .permission-row[_ngcontent-%COMP%] {\n grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;\n padding: 0.625rem 0.75rem;\n }\n}\n\n.role-header[_ngcontent-%COMP%], \n.permission-header[_ngcontent-%COMP%] {\n text-align: left;\n}\n\n.permission-header[_ngcontent-%COMP%] {\n text-align: center;\n}\n\n.role-name[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--mj-text-primary);\n font-size: 0.875rem;\n display: flex;\n align-items: center;\n}\n\n@media (max-width: 639px) {\n .role-name[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n }\n}\n\n.permission-cell[_ngcontent-%COMP%] {\n text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n\n.text-success[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.text-muted[_ngcontent-%COMP%] {\n color: var(--mj-color-neutral-400);\n opacity: 0.6;\n}\n\n.no-permissions[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 0.875rem;\n margin: 0;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n text-align: center;\n}\n\n\n\n\n\n.entities-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 0.75rem;\n grid-template-columns: 1fr;\n}\n\n@media (min-width: 640px) {\n .entities-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .entities-grid[_ngcontent-%COMP%] {\n gap: 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .entities-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(3, 1fr);\n gap: 1.5rem;\n }\n}\n\n\n\n.entity-grid-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n padding: 1.25rem;\n position: relative;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-grid-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-grid-card.access-public[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.entity-grid-card.access-restricted[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.entity-grid-card.access-custom[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-color-warning-500);\n}\n\n@media (min-width: 768px) {\n .entity-grid-card[_ngcontent-%COMP%] {\n padding: 1.5rem;\n }\n}\n\n\n\n.grid-card-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 0.75rem;\n font-size: 1.5rem;\n color: var(--mj-brand-primary);\n}\n\n@media (min-width: 768px) {\n .grid-card-header[_ngcontent-%COMP%] {\n margin-bottom: 1rem;\n }\n}\n\n\n\n.grid-card-title[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n@media (min-width: 768px) {\n .grid-card-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n}\n\n\n\n.grid-card-description[_ngcontent-%COMP%] {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0 0 0.75rem 0;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n@media (min-width: 768px) {\n .grid-card-description[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n margin: 0 0 1rem 0;\n }\n}\n\n\n\n.grid-card-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n}\n\n\n\n.access-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n font-weight: 500;\n}\n\n.permission-count[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n@media (min-width: 768px) {\n .empty-state[_ngcontent-%COMP%] {\n padding: 5rem 2.5rem;\n }\n}\n\n.empty-state[_ngcontent-%COMP%] .empty-state-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n\n\n.error-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n}\n\n@media (min-width: 768px) {\n .error-container[_ngcontent-%COMP%] {\n padding: 5rem 2.5rem;\n }\n}\n\n.error-container[_ngcontent-%COMP%] .error-icon[_ngcontent-%COMP%] {\n margin-bottom: 0.5rem;\n}\n\n\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 800px;\n }\n}\n\n\n\n\n\n@media (max-width: 374px) {\n .filters-section[_ngcontent-%COMP%] {\n padding: 0.5rem;\n margin-bottom: 0.375rem;\n }\n\n .filters-row[_ngcontent-%COMP%] {\n gap: 0.375rem;\n }\n\n .mobile-search-container[_ngcontent-%COMP%] {\n gap: 0.375rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-input[_ngcontent-%COMP%] {\n padding: 0.625rem 0.75rem 0.625rem 2.25rem;\n font-size: 0.875rem;\n }\n\n .mj-search[_ngcontent-%COMP%] .mj-search-icon[_ngcontent-%COMP%] {\n left: 0.75rem;\n font-size: 0.875rem;\n }\n\n .filter-button[_ngcontent-%COMP%] {\n padding: 0.625rem;\n min-width: 40px;\n flex-shrink: 0;\n }\n\n .filter-button[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: none;\n }\n\n .filter-modal-header[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n\n .filter-modal-body[_ngcontent-%COMP%] {\n padding: 1.25rem;\n }\n\n .filter-modal-footer[_ngcontent-%COMP%] {\n padding: 1rem 1.25rem;\n }\n}"] });
|
|
831
832
|
};
|
|
832
833
|
EntityPermissionsComponent = __decorate([
|
|
833
834
|
RegisterClass(BaseDashboard, 'EntityPermissions')
|
|
@@ -835,7 +836,7 @@ EntityPermissionsComponent = __decorate([
|
|
|
835
836
|
export { EntityPermissionsComponent };
|
|
836
837
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityPermissionsComponent, [{
|
|
837
838
|
type: Component,
|
|
838
|
-
args: [{ standalone: false, selector: 'mj-entity-permissions', template: "<div class=\"entity-permissions-container\">\n <!-- Sticky Header Section - Contains controls that should always be visible -->\n <div class=\"sticky-header\">\n <!-- Action Buttons -->\n <div class=\"action-buttons\" role=\"toolbar\" aria-label=\"Entity permissions actions\">\n <div class=\"mj-view-toggle\">\n <button\n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"viewMode === 'list'\"\n (click)=\"setViewMode('list')\"\n (keydown.enter)=\"setViewMode('list')\"\n (keydown.space)=\"setViewMode('list'); $event.preventDefault()\"\n [attr.aria-label]=\"'List view' + (viewMode === 'list' ? ' (active)' : '')\"\n [attr.aria-pressed]=\"viewMode === 'list'\"\n role=\"button\"\n tabindex=\"0\"\n title=\"List View\"\n >\n <i class=\"fa-solid fa-list\" aria-hidden=\"true\"></i>\n </button>\n <button\n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"viewMode === 'grid'\"\n (click)=\"setViewMode('grid')\"\n (keydown.enter)=\"setViewMode('grid')\"\n (keydown.space)=\"setViewMode('grid'); $event.preventDefault()\"\n [attr.aria-label]=\"'Grid view' + (viewMode === 'grid' ? ' (active)' : '')\"\n [attr.aria-pressed]=\"viewMode === 'grid'\"\n role=\"button\"\n tabindex=\"0\"\n title=\"Grid View\"\n >\n <i class=\"fa-solid fa-th\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button\n class=\"mj-btn mj-btn-secondary mj-btn-icon-mobile\"\n (click)=\"refreshData()\"\n [disabled]=\"isLoading\"\n aria-label=\"Refresh entity permissions data\"\n title=\"Refresh\"\n >\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"isLoading\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Refresh</span>\n </button>\n </div>\n\n <!-- Stats Cards -->\n <div class=\"mj-grid-4\" role=\"region\" aria-label=\"Permission statistics\">\n <div class=\"mj-card\" role=\"article\" aria-label=\"Total entities statistic\">\n <div class=\"stat-icon stat-icon-total\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Total entities count\">{{ stats.totalEntities }}</div>\n <div class=\"stat-label\">Total Entities</div>\n </div>\n </div>\n\n <div class=\"mj-card\" role=\"article\" aria-label=\"Public entities statistic\">\n <div class=\"stat-icon stat-icon-public\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-globe\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Public entities count\">{{ stats.publicEntities }}</div>\n <div class=\"stat-label\">Public Entities</div>\n </div>\n </div>\n\n <div class=\"mj-card\" role=\"article\" aria-label=\"Restricted entities statistic\">\n <div class=\"stat-icon stat-icon-restricted\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-lock\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Restricted entities count\">{{ stats.restrictedEntities }}</div>\n <div class=\"stat-label\">Restricted Entities</div>\n </div>\n </div>\n\n <div class=\"mj-card\" role=\"article\" aria-label=\"Total permissions statistic\">\n <div class=\"stat-icon stat-icon-permissions\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Total permissions count\">{{ stats.totalPermissions }}</div>\n <div class=\"stat-label\">Total Permissions</div>\n </div>\n </div>\n </div>\n\n <!-- Filters Section -->\n <div class=\"filters-section\" role=\"search\" aria-label=\"Entity filters\">\n <div class=\"filters-row\">\n <!-- Mobile: Search + Filter Button Container -->\n <div class=\"mobile-search-container\">\n <!-- Entity Search -->\n <div class=\"mj-search\">\n <i class=\"fa-solid fa-search mj-search-icon\" aria-hidden=\"true\"></i>\n <input\n type=\"text\"\n class=\"mj-search-input\"\n placeholder=\"Search entities by name or description...\"\n (input)=\"onSearchChange($event)\"\n [value]=\"filters$.value.entitySearch\"\n aria-label=\"Search entities\"\n />\n </div>\n\n <!-- Filter Button (Mobile Only) -->\n <button\n class=\"filter-button\"\n (click)=\"showMobileFilters = true\"\n aria-label=\"Open filters\"\n >\n <i class=\"fa-solid fa-filter\" aria-hidden=\"true\"></i>\n <span>Filters</span>\n </button>\n </div>\n\n <!-- Access Level Filter -->\n <div class=\"mj-filter-group\">\n <label class=\"mj-filter-label\" id=\"access-level-label\">Access Level</label>\n <div class=\"mj-filter-buttons\" role=\"group\" aria-labelledby=\"access-level-label\">\n <button\n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"filters$.value.accessLevel === 'all'\"\n (click)=\"onAccessLevelChange('all')\"\n [attr.aria-pressed]=\"filters$.value.accessLevel === 'all'\"\n aria-label=\"Show all access levels\"\n >\n All\n </button>\n <button\n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"filters$.value.accessLevel === 'public'\"\n (click)=\"onAccessLevelChange('public')\"\n [attr.aria-pressed]=\"filters$.value.accessLevel === 'public'\"\n aria-label=\"Show only public entities\"\n >\n Public\n </button>\n <button\n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"filters$.value.accessLevel === 'restricted'\"\n (click)=\"onAccessLevelChange('restricted')\"\n [attr.aria-pressed]=\"filters$.value.accessLevel === 'restricted'\"\n aria-label=\"Show only restricted entities\"\n >\n Restricted\n </button>\n <button\n class=\"mj-btn mj-btn-ghost\"\n [class.mj-btn-primary]=\"filters$.value.accessLevel === 'custom'\"\n (click)=\"onAccessLevelChange('custom')\"\n [attr.aria-pressed]=\"filters$.value.accessLevel === 'custom'\"\n aria-label=\"Show only custom access entities\"\n >\n Custom\n </button>\n </div>\n </div>\n\n <!-- Role Filter -->\n <div class=\"mj-filter-group\">\n <label class=\"mj-filter-label\" for=\"role-filter\">Filter by Role</label>\n <select\n id=\"role-filter\"\n class=\"mj-filter-select\"\n (change)=\"onRoleFilterChange($event)\"\n aria-label=\"Filter entities by role\"\n >\n <option value=\"\">All Roles</option>\n @for (role of roles; track role.ID) {\n <option [value]=\"role.ID\">{{ role.Name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div><!-- End Sticky Header -->\n\n <!-- Scrollable Content Section -->\n <div class=\"scrollable-content\">\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-container\" role=\"status\" aria-live=\"polite\" aria-busy=\"true\">\n <mj-loading text=\"Loading entity permissions...\" size=\"medium\"></mj-loading>\n </div>\n }\n\n <!-- Error State -->\n @if (error && !isLoading) {\n <div class=\"error-container\" role=\"alert\" aria-live=\"assertive\">\n <div class=\"error-content\">\n <i class=\"fa-solid fa-exclamation-triangle error-icon\" aria-hidden=\"true\"></i>\n <p class=\"error-message\">{{ error }}</p>\n <button\n class=\"mj-btn mj-btn-primary\"\n (click)=\"loadInitialData()\"\n aria-label=\"Retry loading entity permissions\"\n >\n <i class=\"fa-solid fa-refresh\" aria-hidden=\"true\"></i>\n Try Again\n </button>\n </div>\n </div>\n }\n\n <!-- Content Area -->\n @if (!isLoading && !error) {\n <div class=\"content-area\">\n @if (viewMode === 'list') {\n <!-- List View -->\n <div class=\"entities-list\" role=\"list\" aria-label=\"Entity permissions list\">\n @for (ea of filteredEntityAccess; track ea.entity.ID) {\n <div\n class=\"entity-card\"\n [class.expanded]=\"isEntityExpanded(ea.entity.ID)\"\n role=\"listitem\"\n [attr.aria-expanded]=\"isEntityExpanded(ea.entity.ID)\"\n >\n <div\n class=\"entity-header\"\n (click)=\"toggleEntityExpansion(ea.entity.ID)\"\n (keydown.enter)=\"toggleEntityExpansion(ea.entity.ID)\"\n (keydown.space)=\"toggleEntityExpansion(ea.entity.ID); $event.preventDefault()\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'Expand permissions for ' + ea.entity.Name\"\n >\n <div class=\"entity-info\">\n <div class=\"entity-icon-wrapper\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-table\"></i>\n </div>\n <div class=\"entity-details\">\n <h3 class=\"entity-name\">{{ ea.entity.Name }}</h3>\n <p class=\"entity-description\">{{ ea.entity.Description || 'No description available' }}</p>\n </div>\n </div>\n\n <div class=\"entity-meta\">\n <span\n class=\"access-badge\"\n [class]=\"getAccessLevelClass(ea)\"\n [attr.aria-label]=\"'Access level: ' + getAccessLevelLabel(ea)\"\n >\n <i\n [class]=\"getAccessLevelClass(ea) === 'access-public' ? 'fa-solid fa-globe' :\n getAccessLevelClass(ea) === 'access-restricted' ? 'fa-solid fa-lock' :\n 'fa-solid fa-key'\"\n aria-hidden=\"true\"\n ></i>\n {{ getAccessLevelLabel(ea) }}\n </span>\n <div class=\"entity-actions\" (click)=\"$event.stopPropagation()\">\n <button\n class=\"mj-btn mj-btn-ghost mj-btn-sm\"\n (click)=\"editEntityPermissions(ea)\"\n title=\"Edit Permissions\"\n [attr.aria-label]=\"'Edit permissions for ' + ea.entity.Name\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button\n class=\"expand-btn\"\n [attr.aria-label]=\"(isEntityExpanded(ea.entity.ID) ? 'Collapse' : 'Expand') + ' permissions for ' + ea.entity.Name\"\n >\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n\n @if (isEntityExpanded(ea.entity.ID)) {\n <div class=\"entity-content\" role=\"region\" [attr.aria-label]=\"'Permissions for ' + ea.entity.Name\">\n <!-- Mobile-only actions bar -->\n <div class=\"mobile-actions-bar\" (click)=\"$event.stopPropagation()\">\n <span class=\"access-badge\" [class]=\"getAccessLevelClass(ea)\">\n <i\n [class]=\"getAccessLevelClass(ea) === 'access-public' ? 'fa-solid fa-globe' :\n getAccessLevelClass(ea) === 'access-restricted' ? 'fa-solid fa-lock' :\n 'fa-solid fa-key'\"\n aria-hidden=\"true\"\n ></i>\n {{ getAccessLevelLabel(ea) }}\n </span>\n <div class=\"mobile-action-buttons\">\n <button\n class=\"mj-btn mj-btn-ghost mj-btn-sm\"\n (click)=\"editEntityPermissions(ea)\"\n title=\"Edit Permissions\"\n [attr.aria-label]=\"'Edit permissions for ' + ea.entity.Name\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n <span class=\"btn-label\">Edit</span>\n </button>\n </div>\n </div>\n\n @if (ea.permissions.length > 0) {\n <table class=\"permissions-grid\" role=\"table\" aria-label=\"Role permissions\">\n <thead class=\"permissions-header\" role=\"rowgroup\">\n <tr role=\"row\">\n <th class=\"role-header\" scope=\"col\" role=\"columnheader\">Role</th>\n <th class=\"permission-header\" scope=\"col\" role=\"columnheader\">Create</th>\n <th class=\"permission-header\" scope=\"col\" role=\"columnheader\">Read</th>\n <th class=\"permission-header\" scope=\"col\" role=\"columnheader\">Update</th>\n <th class=\"permission-header\" scope=\"col\" role=\"columnheader\">Delete</th>\n </tr>\n </thead>\n <tbody role=\"rowgroup\">\n @for (roleId of ea.rolePermissions.keys(); track roleId) {\n <tr class=\"permission-row\" role=\"row\">\n <td class=\"role-name\" role=\"cell\">{{ getRoleName(roleId) }}</td>\n <td class=\"permission-cell\" role=\"cell\" [attr.aria-label]=\"'Create: ' + (hasPermission(ea, roleId, 'canCreate') ? 'allowed' : 'denied')\">\n <i\n [class]=\"hasPermission(ea, roleId, 'canCreate') ?\n 'fa-solid fa-check text-success' :\n 'fa-solid fa-times text-muted'\"\n [attr.aria-hidden]=\"true\"\n ></i>\n </td>\n <td class=\"permission-cell\" role=\"cell\" [attr.aria-label]=\"'Read: ' + (hasPermission(ea, roleId, 'canRead') ? 'allowed' : 'denied')\">\n <i\n [class]=\"hasPermission(ea, roleId, 'canRead') ?\n 'fa-solid fa-check text-success' :\n 'fa-solid fa-times text-muted'\"\n [attr.aria-hidden]=\"true\"\n ></i>\n </td>\n <td class=\"permission-cell\" role=\"cell\" [attr.aria-label]=\"'Update: ' + (hasPermission(ea, roleId, 'canUpdate') ? 'allowed' : 'denied')\">\n <i\n [class]=\"hasPermission(ea, roleId, 'canUpdate') ?\n 'fa-solid fa-check text-success' :\n 'fa-solid fa-times text-muted'\"\n [attr.aria-hidden]=\"true\"\n ></i>\n </td>\n <td class=\"permission-cell\" role=\"cell\" [attr.aria-label]=\"'Delete: ' + (hasPermission(ea, roleId, 'canDelete') ? 'allowed' : 'denied')\">\n <i\n [class]=\"hasPermission(ea, roleId, 'canDelete') ?\n 'fa-solid fa-check text-success' :\n 'fa-solid fa-times text-muted'\"\n [attr.aria-hidden]=\"true\"\n ></i>\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <p class=\"no-permissions\">\n @if (ea.isPublic) {\n This entity is publicly accessible by all users.\n } @else {\n No specific role permissions configured. Access is restricted to system administrators.\n }\n </p>\n }\n </div>\n }\n </div>\n }\n </div>\n } @else {\n <!-- Grid View -->\n <div class=\"entities-grid\" role=\"list\" aria-label=\"Entity permissions grid\">\n @for (ea of filteredEntityAccess; track ea.entity.ID) {\n <article\n class=\"entity-grid-card\"\n [class]=\"getAccessLevelClass(ea)\"\n [attr.aria-label]=\"'Entity: ' + ea.entity.Name\"\n >\n <div class=\"grid-card-header\">\n <i class=\"fa-solid fa-table\" aria-hidden=\"true\"></i>\n <button\n class=\"mj-btn mj-btn-ghost mj-btn-sm\"\n (click)=\"editEntityPermissions(ea)\"\n [attr.aria-label]=\"'Edit permissions for ' + ea.entity.Name\"\n title=\"Edit Permissions\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <h4 class=\"grid-card-title\">{{ ea.entity.Name }}</h4>\n <p class=\"grid-card-description\">{{ ea.entity.Description || 'No description' }}</p>\n <div class=\"grid-card-footer\">\n <span\n class=\"access-label\"\n [attr.aria-label]=\"'Access level: ' + getAccessLevelLabel(ea)\"\n >\n <i\n [class]=\"getAccessLevelClass(ea) === 'access-public' ? 'fa-solid fa-globe' :\n getAccessLevelClass(ea) === 'access-restricted' ? 'fa-solid fa-lock' :\n 'fa-solid fa-key'\"\n aria-hidden=\"true\"\n ></i>\n {{ getAccessLevelLabel(ea) }}\n </span>\n @if (ea.permissions.length > 0) {\n <span\n class=\"permission-count\"\n [attr.aria-label]=\"ea.permissions.length + ' permission' + (ea.permissions.length === 1 ? '' : 's')\"\n >\n {{ ea.permissions.length }} permission{{ ea.permissions.length === 1 ? '' : 's' }}\n </span>\n }\n </div>\n </article>\n }\n </div>\n }\n\n @if (filteredEntityAccess.length === 0) {\n <div class=\"empty-state\" role=\"status\">\n <i class=\"fa-solid fa-shield-alt empty-state-icon\" aria-hidden=\"true\"></i>\n <h3 class=\"empty-text\">No Permissions Found</h3>\n <p class=\"empty-subtext\">Try adjusting your filters or refresh the data.</p>\n <button\n class=\"mj-btn mj-btn-primary\"\n (click)=\"refreshData()\"\n aria-label=\"Refresh permissions data\"\n >\n <i class=\"fa-solid fa-refresh\" aria-hidden=\"true\"></i>\n Refresh\n </button>\n </div>\n }\n </div>\n }\n </div><!-- End Scrollable Content -->\n\n <!-- Permission Edit Dialog -->\n <mj-permission-dialog\n [visible]=\"showPermissionDialog\"\n [data]=\"permissionDialogData\"\n (result)=\"onPermissionDialogResult($event)\"\n ></mj-permission-dialog>\n\n <!-- Mobile Filter Modal -->\n @if (showMobileFilters) {\n <div\n class=\"filter-modal-backdrop\"\n (click)=\"showMobileFilters = false\"\n role=\"presentation\"\n >\n <div\n class=\"filter-modal\"\n (click)=\"$event.stopPropagation()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"filter-modal-title\"\n >\n <div class=\"filter-modal-header\">\n <h3 class=\"filter-modal-title\" id=\"filter-modal-title\">\n <i class=\"fa-solid fa-filter\" aria-hidden=\"true\"></i>\n Filters\n </h3>\n <button\n class=\"filter-modal-close\"\n (click)=\"showMobileFilters = false\"\n aria-label=\"Close filters\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <div class=\"filter-modal-body\">\n <div class=\"filter-options-container\">\n <!-- Access Level Filter -->\n <div class=\"filter-group\">\n <h4 class=\"filter-group-label\">Access Level</h4>\n <div class=\"filter-group-options\">\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.accessLevel === 'all'\"\n >\n <input\n type=\"radio\"\n name=\"accessLevel\"\n value=\"all\"\n [checked]=\"filters$.value.accessLevel === 'all'\"\n (change)=\"onAccessLevelChange('all')\"\n />\n <span class=\"filter-option-label\">All Levels</span>\n </label>\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.accessLevel === 'public'\"\n >\n <input\n type=\"radio\"\n name=\"accessLevel\"\n value=\"public\"\n [checked]=\"filters$.value.accessLevel === 'public'\"\n (change)=\"onAccessLevelChange('public')\"\n />\n <span class=\"filter-option-label\">Public Entities</span>\n </label>\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.accessLevel === 'restricted'\"\n >\n <input\n type=\"radio\"\n name=\"accessLevel\"\n value=\"restricted\"\n [checked]=\"filters$.value.accessLevel === 'restricted'\"\n (change)=\"onAccessLevelChange('restricted')\"\n />\n <span class=\"filter-option-label\">Restricted Entities</span>\n </label>\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.accessLevel === 'custom'\"\n >\n <input\n type=\"radio\"\n name=\"accessLevel\"\n value=\"custom\"\n [checked]=\"filters$.value.accessLevel === 'custom'\"\n (change)=\"onAccessLevelChange('custom')\"\n />\n <span class=\"filter-option-label\">Custom Access Entities</span>\n </label>\n </div>\n </div>\n\n <!-- Role Filter -->\n <div class=\"filter-group\">\n <h4 class=\"filter-group-label\">Filter by Role</h4>\n <div class=\"filter-group-options\">\n <label class=\"filter-option\" [class.selected]=\"!filters$.value.roleId\">\n <input\n type=\"radio\"\n name=\"role\"\n value=\"\"\n [checked]=\"!filters$.value.roleId\"\n (change)=\"onRoleFilterChange($event)\"\n />\n <span class=\"filter-option-label\">All Roles</span>\n </label>\n @for (role of roles; track role.ID) {\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.roleId === role.ID\"\n >\n <input\n type=\"radio\"\n name=\"role\"\n [value]=\"role.ID\"\n [checked]=\"filters$.value.roleId === role.ID\"\n (change)=\"onRoleFilterChange($event)\"\n />\n <span class=\"filter-option-label\">{{ role.Name }}</span>\n </label>\n }\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"filter-modal-footer\">\n <button\n class=\"mj-btn mj-btn-primary\"\n (click)=\"showMobileFilters = false\"\n >\n Apply Filters\n </button>\n <button\n class=\"mj-btn mj-btn-secondary\"\n (click)=\"showMobileFilters = false\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n", styles: ["/* =============================================================================\n Shared Admin Patterns - MJ Design System\n Common styles shared across all admin settings components.\n Component-specific CSS files override these values where needed.\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Host & Container\n ----------------------------------------------------------------------------- */\n:host {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* -----------------------------------------------------------------------------\n Sticky Header\n ----------------------------------------------------------------------------- */\n.sticky-header {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n/* -----------------------------------------------------------------------------\n Scrollable Content\n ----------------------------------------------------------------------------- */\n.scrollable-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content {\n padding: 2rem 2.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons (In Sticky Header)\n ----------------------------------------------------------------------------- */\n.action-buttons {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .mj-btn-icon-mobile .btn-text {\n display: none;\n }\n\n .mj-btn-icon-mobile {\n padding: 0.5rem 0.75rem;\n min-height: 40px;\n gap: 0;\n border-radius: var(--mj-radius-full);\n }\n\n .mj-btn-icon-mobile i {\n font-size: 1.125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Statistics Cards Grid - Static Display (Non-interactive)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4 {\n gap: 1rem;\n }\n}\n\n/* Static Card - No hover effects */\n.mj-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card {\n padding: 1rem 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Stat Icon Containers\n ----------------------------------------------------------------------------- */\n.stat-icon {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Stat Content Typography\n ----------------------------------------------------------------------------- */\n.stat-content {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content .stat-value {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-value {\n font-size: 2rem;\n }\n}\n\n.stat-content .stat-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-label {\n font-size: 0.8125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Filters Section\n ----------------------------------------------------------------------------- */\n.filters-section {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-filter-buttons .mj-btn {\n border-radius: var(--mj-radius-full);\n}\n\n.mj-filter-buttons .mj-btn-primary {\n background-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* -----------------------------------------------------------------------------\n Search Input\n ----------------------------------------------------------------------------- */\n.mj-search {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search .mj-search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-icon {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search .mj-search-input {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search .mj-search-input {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search .mj-search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search .mj-search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search .mj-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search:focus-within .mj-search-icon {\n color: var(--mj-brand-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Content Area\n ----------------------------------------------------------------------------- */\n.content-area {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area {\n padding: 1.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Expand Button\n ----------------------------------------------------------------------------- */\n.expand-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn i {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Status Badge\n ----------------------------------------------------------------------------- */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge i {\n font-size: 0.625rem;\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Actions Bar\n ----------------------------------------------------------------------------- */\n.mobile-actions-bar {\n display: none;\n}\n\n.mobile-action-buttons {\n display: flex;\n gap: 0.5rem;\n}\n\n/* -----------------------------------------------------------------------------\n Empty State\n ----------------------------------------------------------------------------- */\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state .empty-icon {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state .empty-subtext {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Loading State\n ----------------------------------------------------------------------------- */\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n/* -----------------------------------------------------------------------------\n Error State\n ----------------------------------------------------------------------------- */\n.error-container {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container .error-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container .error-icon {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container .error-message {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Dialog\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header .modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header .modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body {\n padding: 1.5rem;\n}\n\n.modal-body p {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body p:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header {\n padding: 1rem;\n }\n\n .modal-header .modal-title {\n font-size: 1.125rem;\n }\n\n .modal-body {\n padding: 1rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n .modal-footer .mj-btn {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* -----------------------------------------------------------------------------\n MJ Button System\n ----------------------------------------------------------------------------- */\n.mj-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n min-height: 44px;\n}\n\n.mj-btn:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n/* Primary Button */\n.mj-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-primary:active:not(:disabled) {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n/* Secondary Button */\n.mj-btn-secondary {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n}\n\n.mj-btn-secondary:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-btn-secondary:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n border-color: var(--mj-color-brand-700);\n}\n\n/* Ghost Button */\n.mj-btn-ghost {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n\n.mj-btn-ghost:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-btn-ghost:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n}\n\n/* Danger Button */\n.mj-btn-danger {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-danger:hover:not(:disabled) {\n background: var(--mj-color-error-300);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-danger:active:not(:disabled) {\n background: var(--mj-color-error-200);\n transform: scale(0.98);\n}\n\n/* Small Button */\n.mj-btn-sm {\n padding: 0.5rem 0.875rem;\n font-size: 0.8125rem;\n min-height: 36px;\n}\n\n/* Icon-only Button */\n.mj-btn-icon-only {\n padding: 0.625rem;\n min-width: 44px;\n min-height: 44px;\n}\n\n/* Icon-mobile Button (text hidden on small screens) */\n.mj-btn-icon-mobile {\n gap: 0.5rem;\n}\n\n.mj-btn-icon-mobile .btn-text {\n display: inline;\n}\n\n/* Ghost Danger Button */\n.mj-btn-ghost.mj-btn-danger {\n background: transparent;\n color: var(--mj-status-error);\n box-shadow: none;\n}\n\n.mj-btn-ghost.mj-btn-danger:hover:not(:disabled) {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n/* -----------------------------------------------------------------------------\n Filter Button (Mobile Only)\n ----------------------------------------------------------------------------- */\n.filter-button {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button i {\n font-size: 1rem;\n}\n\n/* -----------------------------------------------------------------------------\n Filter Modal (Mobile Bottom Sheet)\n ----------------------------------------------------------------------------- */\n.filter-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title i {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer button {\n flex: 1;\n margin: 0;\n}\n\n/* Filter Options Container (Inside Modal) */\n.filter-options-container {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option input[type=\"checkbox\"],\n.filter-option input[type=\"radio\"] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected .filter-option-label {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* -----------------------------------------------------------------------------\n Utility Classes\n ----------------------------------------------------------------------------- */\n.text-danger {\n color: var(--mj-status-error);\n}\n\n.text-warning {\n color: var(--mj-color-warning-500);\n}\n\n.text-success {\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Animations\n ----------------------------------------------------------------------------- */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Focus Indicators\n ----------------------------------------------------------------------------- */\n.mj-search-input:focus-visible,\nbutton:focus-visible,\n.mj-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Reduced Motion\n ----------------------------------------------------------------------------- */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n", "/* =============================================================================\n Entity Permissions Component - Component-Specific Styles\n Shared patterns are in ../shared/styles/_admin-patterns.css\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Container\n ----------------------------------------------------------------------------- */\n.entity-permissions-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n position: relative;\n margin: 0 auto;\n width: 100%;\n background: var(--mj-bg-page);\n}\n\n/* -----------------------------------------------------------------------------\n Sticky Header Override - Has explicit padding values\n ----------------------------------------------------------------------------- */\n.sticky-header {\n padding: 1rem;\n}\n\n@media (min-width: 640px) {\n .sticky-header {\n padding: 1.25rem;\n }\n}\n\n@media (min-width: 768px) {\n .sticky-header {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .sticky-header {\n padding: 1.5rem 2rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Scrollable Content Override - Different breakpoints\n ----------------------------------------------------------------------------- */\n@media (min-width: 640px) {\n .scrollable-content {\n padding: 1.25rem;\n }\n}\n\n@media (min-width: 768px) {\n .scrollable-content {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content {\n padding: 1.5rem 2rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Button Override - min-width and text-decoration\n ----------------------------------------------------------------------------- */\n.mj-btn {\n min-width: 44px;\n text-decoration: none;\n}\n\n/* Ghost Button Override - Different padding */\n.mj-btn-ghost {\n padding: 0.75rem 1rem;\n}\n\n/* Small Button Override - Different min-width */\n.mj-btn-sm {\n min-width: 36px;\n}\n\n/* Icon-mobile Override */\n.mj-btn-icon-mobile {\n padding: 0.75rem 1.5rem;\n}\n\n@media (min-width: 640px) {\n .mj-btn-icon-mobile {\n padding: 0.75rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .mj-btn-icon-mobile .btn-text {\n display: none;\n }\n\n .mj-btn-icon-mobile {\n padding: 0.625rem;\n gap: 0;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons Override - Different layout (space-between with margin)\n ----------------------------------------------------------------------------- */\n.action-buttons {\n justify-content: space-between;\n margin-bottom: 1rem;\n flex-wrap: wrap;\n align-items: center;\n padding: 0;\n background: transparent;\n}\n\n@media (min-width: 768px) {\n .action-buttons {\n margin-bottom: 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Navigation Rail\n ----------------------------------------------------------------------------- */\n@media (max-width: 639px) {\n .sticky-header {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n }\n\n .action-buttons {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n margin-bottom: 0;\n order: 1;\n width: 100%;\n }\n\n .mj-view-toggle {\n flex-shrink: 0;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n padding: 3px;\n gap: 2px;\n }\n\n .mj-view-toggle .mj-btn {\n padding: 0.5rem 0.625rem;\n min-width: 36px;\n min-height: 36px;\n border-radius: var(--mj-radius-md);\n }\n\n .mj-view-toggle .mj-btn.mj-btn-primary {\n box-shadow: none;\n }\n\n .action-buttons > .mj-btn-secondary {\n flex-shrink: 0;\n padding: 0.5rem 0.625rem;\n min-width: 36px;\n min-height: 36px;\n border-radius: var(--mj-radius-lg);\n }\n\n .filters-section {\n order: 2;\n width: 100%;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 0.75rem;\n margin-bottom: 0.5rem;\n border-radius: var(--mj-radius-lg);\n }\n\n .filters-row {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 0.5rem;\n flex-wrap: nowrap;\n }\n\n /* Mobile search container */\n .mobile-search-container {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n flex: 1;\n min-width: 0;\n }\n\n .mj-search {\n flex: 1;\n min-width: 0;\n }\n\n .mj-search .mj-search-input {\n padding: 0.75rem 1rem 0.75rem 2.5rem;\n min-height: 44px;\n font-size: 1rem;\n border-width: 1.5px;\n border-radius: var(--mj-radius-full);\n box-sizing: border-box;\n width: 100%;\n }\n\n .mj-search .mj-search-icon {\n left: 0.875rem;\n font-size: 1rem;\n }\n\n .mj-search .mj-search-input::placeholder {\n font-size: 0.875rem;\n }\n\n /* Hide filter groups on mobile - they go in modal */\n .mj-filter-group {\n display: none !important;\n }\n\n .mj-filter-label {\n display: none;\n }\n\n .mj-filter-select {\n display: none;\n }\n}\n\n/* -----------------------------------------------------------------------------\n View Toggle\n ----------------------------------------------------------------------------- */\n.mj-view-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-view-toggle .mj-btn {\n padding: 0.5rem 1rem;\n border-radius: var(--mj-radius-full);\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n font-size: 0.875rem;\n font-weight: 500;\n}\n\n.mj-view-toggle .mj-btn:hover:not(:disabled):not(.mj-btn-primary) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-view-toggle .mj-btn.mj-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* -----------------------------------------------------------------------------\n Stats Grid Override - Different layout (margin-based, hidden on mobile)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n margin-bottom: 1rem;\n width: 100%;\n padding: 0;\n background: transparent;\n}\n\n@media (max-width: 639px) {\n .mj-grid-4 {\n display: none !important;\n }\n}\n\n@media (min-width: 640px) {\n .mj-grid-4 {\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n gap: 1.25rem;\n margin-bottom: 1.25rem;\n }\n}\n\n/* Stat Card Override - min-width and no box-shadow */\n.mj-card {\n min-width: 0;\n box-shadow: none;\n}\n\n/* Stat Value Override at 768px - different size */\n@media (min-width: 768px) {\n .stat-content .stat-value {\n font-size: 1.875rem;\n }\n}\n\n/* Stat Icon Override - Component-specific colors */\n.stat-icon-public {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n.stat-icon-restricted {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-permissions {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n/* -----------------------------------------------------------------------------\n Filters Section Override - Different layout (no margin, full width)\n ----------------------------------------------------------------------------- */\n.filters-section {\n border-radius: var(--mj-radius-xl);\n padding: 1rem;\n margin-bottom: 0;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n@media (min-width: 768px) {\n .filters-section {\n padding: 1rem 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .filters-section {\n padding: 1.25rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .filters-row {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .filters-row {\n gap: 1.5rem;\n }\n}\n\n/* Search Input Override at 1024px - different padding */\n@media (min-width: 1024px) {\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3rem;\n }\n\n .mj-search .mj-search-icon {\n left: 1.125rem;\n font-size: 1.125rem;\n }\n}\n\n/* Filter Button Overrides */\n.mj-filter-buttons {\n flex-wrap: wrap;\n}\n\n.mj-filter-buttons .mj-btn {\n padding: 0.5rem 1rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 500;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n}\n\n.mj-filter-buttons .mj-btn:hover:not(:disabled):not(.mj-btn-primary) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-filter-buttons .mj-btn.mj-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n@media (max-width: 639px) {\n .mj-filter-buttons {\n flex-direction: row;\n flex-wrap: wrap;\n }\n\n .mj-filter-buttons .mj-btn {\n flex: 1;\n min-width: calc(50% - 4px);\n padding: 0.5rem 0.75rem;\n font-size: 0.75rem;\n }\n}\n\n/* Filter Label Override */\n.mj-filter-label {\n font-size: 0.8125rem;\n line-height: 1.2;\n}\n\n/* Filter Select Dropdown */\n.mj-filter-select {\n padding: 0.5rem 1rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 500;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n height: 44px;\n min-width: 150px;\n box-sizing: border-box;\n}\n\n.mj-filter-select:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-filter-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n@media (max-width: 639px) {\n .mj-filter-select {\n width: 100%;\n }\n}\n\n/* Mobile Search Container (Desktop Default) */\n.mobile-search-container {\n display: contents;\n}\n\n/* Filter Button Badge Override */\n.filter-button .filter-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.625rem;\n font-weight: 700;\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n}\n\n/* Loading Container Override - different layout */\n.loading-container {\n min-height: 200px;\n padding: 3rem 1.5rem;\n flex-direction: row;\n}\n\n/* -----------------------------------------------------------------------------\n Content Area Override - Different background and shadow\n ----------------------------------------------------------------------------- */\n.content-area {\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-md);\n padding: 1.25rem;\n}\n\n@media (min-width: 1024px) {\n .content-area {\n padding: 1.75rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Entities List\n ----------------------------------------------------------------------------- */\n.entities-list {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n overflow: visible;\n}\n\n@media (min-width: 768px) {\n .entities-list {\n gap: 1rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Entity Card - Interactive\n ----------------------------------------------------------------------------- */\n.entity-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-card:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-card.expanded {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-card.expanded .expand-btn i {\n transform: rotate(180deg);\n}\n\n/* Entity Header */\n.entity-header {\n padding: 1rem;\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n gap: 0.75rem;\n}\n\n.entity-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .entity-header {\n padding: 1.25rem 1.5rem;\n }\n}\n\n/* Entity Info */\n.entity-info {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n@media (min-width: 768px) {\n .entity-info {\n gap: 1rem;\n }\n}\n\n/* Entity Icon Container */\n.entity-icon-wrapper {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n background: var(--mj-color-accent-300);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-brand-primary);\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .entity-icon-wrapper {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n/* Entity Details */\n.entity-details {\n flex: 1;\n min-width: 0;\n}\n\n.entity-details .entity-name {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.25rem 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .entity-details .entity-name {\n font-size: 1.125rem;\n }\n}\n\n.entity-details .entity-description {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .entity-details .entity-description {\n font-size: 0.875rem;\n }\n}\n\n/* Entity Meta */\n.entity-meta {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .entity-meta {\n gap: 0.75rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Access Badges\n ----------------------------------------------------------------------------- */\n.access-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .access-badge {\n padding: 0.5rem 1rem;\n font-size: 0.8125rem;\n }\n}\n\n.access-badge.access-public {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.access-badge.access-restricted {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.access-badge.access-custom {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n/* Entity Actions - Hide on mobile */\n.entity-actions {\n display: none;\n}\n\n@media (min-width: 640px) {\n .entity-actions {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n@media (max-width: 639px) {\n .entity-meta > .access-badge {\n display: none;\n }\n}\n\n/* Expand Button Override - inline-flex, different transition */\n.expand-btn {\n display: inline-flex;\n}\n\n.expand-btn i {\n transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Entity Content - Expanded Area\n ----------------------------------------------------------------------------- */\n.entity-content {\n padding: 1.25rem;\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@media (min-width: 768px) {\n .entity-content {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .entity-content {\n padding: 1.75rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Actions Bar\n ----------------------------------------------------------------------------- */\n@media (max-width: 639px) {\n .mobile-actions-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.75rem;\n margin: -1.25rem -1.25rem 1rem -1.25rem;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .mobile-action-buttons {\n display: flex;\n gap: 0.5rem;\n }\n\n .mobile-action-buttons .mj-btn {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n }\n\n .mobile-action-buttons .btn-label {\n font-size: 0.8125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Permissions Grid (Table)\n ----------------------------------------------------------------------------- */\n.permissions-grid {\n width: 100%;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n border-collapse: collapse;\n}\n\n/* Permissions Header */\n.permissions-header tr {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr 1fr;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n@media (min-width: 768px) {\n .permissions-header tr {\n padding: 1rem 1.25rem;\n gap: 0.75rem;\n }\n}\n\n@media (max-width: 639px) {\n .permissions-header tr {\n grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;\n padding: 0.625rem 0.75rem;\n font-size: 0.75rem;\n }\n}\n\n/* Permission Row */\n.permission-row {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr 1fr;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n transition: background-color 0.2s ease;\n}\n\n.permission-row:hover {\n background: var(--mj-bg-surface);\n}\n\n.permission-row:last-child {\n border-bottom: none;\n}\n\n@media (min-width: 768px) {\n .permission-row {\n padding: 1rem 1.25rem;\n gap: 0.75rem;\n }\n}\n\n@media (max-width: 639px) {\n .permission-row {\n grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;\n padding: 0.625rem 0.75rem;\n }\n}\n\n.role-header,\n.permission-header {\n text-align: left;\n}\n\n.permission-header {\n text-align: center;\n}\n\n.role-name {\n font-weight: 500;\n color: var(--mj-text-primary);\n font-size: 0.875rem;\n display: flex;\n align-items: center;\n}\n\n@media (max-width: 639px) {\n .role-name {\n font-size: 0.75rem;\n }\n}\n\n.permission-cell {\n text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Success text */\n.text-success {\n color: var(--mj-status-success);\n}\n\n.text-muted {\n color: var(--mj-color-neutral-400);\n opacity: 0.6;\n}\n\n.no-permissions {\n color: var(--mj-text-secondary);\n font-size: 0.875rem;\n margin: 0;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n text-align: center;\n}\n\n/* -----------------------------------------------------------------------------\n Entities Grid (Grid View)\n ----------------------------------------------------------------------------- */\n.entities-grid {\n display: grid;\n gap: 0.75rem;\n grid-template-columns: 1fr;\n}\n\n@media (min-width: 640px) {\n .entities-grid {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .entities-grid {\n gap: 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .entities-grid {\n grid-template-columns: repeat(3, 1fr);\n gap: 1.5rem;\n }\n}\n\n/* Entity Grid Card */\n.entity-grid-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n padding: 1.25rem;\n position: relative;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-grid-card:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-grid-card.access-public {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.entity-grid-card.access-restricted {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.entity-grid-card.access-custom {\n border-left: 4px solid var(--mj-color-warning-500);\n}\n\n@media (min-width: 768px) {\n .entity-grid-card {\n padding: 1.5rem;\n }\n}\n\n/* Grid Card Header */\n.grid-card-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 0.75rem;\n font-size: 1.5rem;\n color: var(--mj-brand-primary);\n}\n\n@media (min-width: 768px) {\n .grid-card-header {\n margin-bottom: 1rem;\n }\n}\n\n/* Grid Card Title */\n.grid-card-title {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n@media (min-width: 768px) {\n .grid-card-title {\n font-size: 1.125rem;\n }\n}\n\n/* Grid Card Description */\n.grid-card-description {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0 0 0.75rem 0;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n@media (min-width: 768px) {\n .grid-card-description {\n font-size: 0.875rem;\n margin: 0 0 1rem 0;\n }\n}\n\n/* Grid Card Footer */\n.grid-card-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n}\n\n/* Access Label */\n.access-label {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n font-weight: 500;\n}\n\n.permission-count {\n color: var(--mj-text-secondary);\n}\n\n/* -----------------------------------------------------------------------------\n Empty State Override - flex layout with gap\n ----------------------------------------------------------------------------- */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n@media (min-width: 768px) {\n .empty-state {\n padding: 5rem 2.5rem;\n }\n}\n\n.empty-state .empty-state-icon {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n/* Error Container Override - flex layout with min-height */\n.error-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n}\n\n@media (min-width: 768px) {\n .error-container {\n padding: 5rem 2.5rem;\n }\n}\n\n.error-container .error-icon {\n margin-bottom: 0.5rem;\n}\n\n/* slideDown Override - uses max-height instead of translateY */\n@keyframes slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 800px;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Very Small Mobile (< 375px)\n ----------------------------------------------------------------------------- */\n@media (max-width: 374px) {\n .filters-section {\n padding: 0.5rem;\n margin-bottom: 0.375rem;\n }\n\n .filters-row {\n gap: 0.375rem;\n }\n\n .mobile-search-container {\n gap: 0.375rem;\n }\n\n .mj-search .mj-search-input {\n padding: 0.625rem 0.75rem 0.625rem 2.25rem;\n font-size: 0.875rem;\n }\n\n .mj-search .mj-search-icon {\n left: 0.75rem;\n font-size: 0.875rem;\n }\n\n .filter-button {\n padding: 0.625rem;\n min-width: 40px;\n flex-shrink: 0;\n }\n\n .filter-button span {\n display: none;\n }\n\n .filter-modal-header {\n padding: 1rem 1.25rem;\n }\n\n .filter-modal-body {\n padding: 1.25rem;\n }\n\n .filter-modal-footer {\n padding: 1rem 1.25rem;\n }\n}\n"] }]
|
|
839
|
+
args: [{ standalone: false, selector: 'mj-entity-permissions', template: "<div class=\"entity-permissions-container\">\n <!-- Sticky Header Section - Contains controls that should always be visible -->\n <div class=\"sticky-header\">\n <!-- Action Buttons -->\n <div class=\"action-buttons\" role=\"toolbar\" aria-label=\"Entity permissions actions\">\n <div class=\"mj-view-toggle\">\n <button mjButton\n [variant]=\"viewMode === 'list' ? 'primary' : 'flat'\"\n (click)=\"setViewMode('list')\"\n (keydown.enter)=\"setViewMode('list')\"\n (keydown.space)=\"setViewMode('list'); $event.preventDefault()\"\n [attr.aria-label]=\"'List view' + (viewMode === 'list' ? ' (active)' : '')\"\n [attr.aria-pressed]=\"viewMode === 'list'\"\n role=\"button\"\n tabindex=\"0\"\n title=\"List View\"\n >\n <i class=\"fa-solid fa-list\" aria-hidden=\"true\"></i>\n </button>\n <button mjButton\n [variant]=\"viewMode === 'grid' ? 'primary' : 'flat'\"\n (click)=\"setViewMode('grid')\"\n (keydown.enter)=\"setViewMode('grid')\"\n (keydown.space)=\"setViewMode('grid'); $event.preventDefault()\"\n [attr.aria-label]=\"'Grid view' + (viewMode === 'grid' ? ' (active)' : '')\"\n [attr.aria-pressed]=\"viewMode === 'grid'\"\n role=\"button\"\n tabindex=\"0\"\n title=\"Grid View\"\n >\n <i class=\"fa-solid fa-th\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button\n mjButton variant=\"secondary\" class=\"mj-btn-icon-mobile\"\n (click)=\"refreshData()\"\n [disabled]=\"isLoading\"\n aria-label=\"Refresh entity permissions data\"\n title=\"Refresh\"\n >\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"isLoading\" aria-hidden=\"true\"></i>\n <span class=\"btn-text\">Refresh</span>\n </button>\n </div>\n\n <!-- Stats Cards -->\n <div class=\"mj-grid-4\" role=\"region\" aria-label=\"Permission statistics\">\n <div class=\"mj-card\" role=\"article\" aria-label=\"Total entities statistic\">\n <div class=\"stat-icon stat-icon-total\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Total entities count\">{{ stats.totalEntities }}</div>\n <div class=\"stat-label\">Total Entities</div>\n </div>\n </div>\n\n <div class=\"mj-card\" role=\"article\" aria-label=\"Public entities statistic\">\n <div class=\"stat-icon stat-icon-public\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-globe\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Public entities count\">{{ stats.publicEntities }}</div>\n <div class=\"stat-label\">Public Entities</div>\n </div>\n </div>\n\n <div class=\"mj-card\" role=\"article\" aria-label=\"Restricted entities statistic\">\n <div class=\"stat-icon stat-icon-restricted\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-lock\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Restricted entities count\">{{ stats.restrictedEntities }}</div>\n <div class=\"stat-label\">Restricted Entities</div>\n </div>\n </div>\n\n <div class=\"mj-card\" role=\"article\" aria-label=\"Total permissions statistic\">\n <div class=\"stat-icon stat-icon-permissions\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-key\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" aria-label=\"Total permissions count\">{{ stats.totalPermissions }}</div>\n <div class=\"stat-label\">Total Permissions</div>\n </div>\n </div>\n </div>\n\n <!-- Filters Section -->\n <div class=\"filters-section\" role=\"search\" aria-label=\"Entity filters\">\n <div class=\"filters-row\">\n <!-- Mobile: Search + Filter Button Container -->\n <div class=\"mobile-search-container\">\n <!-- Entity Search -->\n <div class=\"mj-search\">\n <i class=\"fa-solid fa-search mj-search-icon\" aria-hidden=\"true\"></i>\n <input\n type=\"text\"\n class=\"mj-search-input\"\n placeholder=\"Search entities by name or description...\"\n (input)=\"onSearchChange($event)\"\n [value]=\"filters$.value.entitySearch\"\n aria-label=\"Search entities\"\n />\n </div>\n\n <!-- Filter Button (Mobile Only) -->\n <button\n class=\"filter-button\"\n (click)=\"showMobileFilters = true\"\n aria-label=\"Open filters\"\n >\n <i class=\"fa-solid fa-filter\" aria-hidden=\"true\"></i>\n <span>Filters</span>\n </button>\n </div>\n\n <!-- Access Level Filter -->\n <div class=\"mj-filter-group\">\n <label class=\"mj-filter-label\" id=\"access-level-label\">Access Level</label>\n <div class=\"mj-filter-buttons\" role=\"group\" aria-labelledby=\"access-level-label\">\n <button mjButton\n [variant]=\"filters$.value.accessLevel === 'all' ? 'primary' : 'flat'\"\n (click)=\"onAccessLevelChange('all')\"\n [attr.aria-pressed]=\"filters$.value.accessLevel === 'all'\"\n aria-label=\"Show all access levels\"\n >\n All\n </button>\n <button mjButton\n [variant]=\"filters$.value.accessLevel === 'public' ? 'primary' : 'flat'\"\n (click)=\"onAccessLevelChange('public')\"\n [attr.aria-pressed]=\"filters$.value.accessLevel === 'public'\"\n aria-label=\"Show only public entities\"\n >\n Public\n </button>\n <button mjButton\n [variant]=\"filters$.value.accessLevel === 'restricted' ? 'primary' : 'flat'\"\n (click)=\"onAccessLevelChange('restricted')\"\n [attr.aria-pressed]=\"filters$.value.accessLevel === 'restricted'\"\n aria-label=\"Show only restricted entities\"\n >\n Restricted\n </button>\n <button mjButton\n [variant]=\"filters$.value.accessLevel === 'custom' ? 'primary' : 'flat'\"\n (click)=\"onAccessLevelChange('custom')\"\n [attr.aria-pressed]=\"filters$.value.accessLevel === 'custom'\"\n aria-label=\"Show only custom access entities\"\n >\n Custom\n </button>\n </div>\n </div>\n\n <!-- Role Filter -->\n <div class=\"mj-filter-group\">\n <label class=\"mj-filter-label\" for=\"role-filter\">Filter by Role</label>\n <select\n id=\"role-filter\"\n class=\"mj-filter-select\"\n (change)=\"onRoleFilterChange($event)\"\n aria-label=\"Filter entities by role\"\n >\n <option value=\"\">All Roles</option>\n @for (role of roles; track role.ID) {\n <option [value]=\"role.ID\">{{ role.Name }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div><!-- End Sticky Header -->\n\n <!-- Scrollable Content Section -->\n <div class=\"scrollable-content\">\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-container\" role=\"status\" aria-live=\"polite\" aria-busy=\"true\">\n <mj-loading text=\"Loading entity permissions...\" size=\"medium\"></mj-loading>\n </div>\n }\n\n <!-- Error State -->\n @if (error && !isLoading) {\n <div class=\"error-container\" role=\"alert\" aria-live=\"assertive\">\n <div class=\"error-content\">\n <i class=\"fa-solid fa-exclamation-triangle error-icon\" aria-hidden=\"true\"></i>\n <p class=\"error-message\">{{ error }}</p>\n <button\n mjButton variant=\"primary\"\n (click)=\"loadInitialData()\"\n aria-label=\"Retry loading entity permissions\"\n >\n <i class=\"fa-solid fa-refresh\" aria-hidden=\"true\"></i>\n Try Again\n </button>\n </div>\n </div>\n }\n\n <!-- Content Area -->\n @if (!isLoading && !error) {\n <div class=\"content-area\">\n @if (viewMode === 'list') {\n <!-- List View -->\n <div class=\"entities-list\" role=\"list\" aria-label=\"Entity permissions list\">\n @for (ea of filteredEntityAccess; track ea.entity.ID) {\n <div\n class=\"entity-card\"\n [class.expanded]=\"isEntityExpanded(ea.entity.ID)\"\n role=\"listitem\"\n [attr.aria-expanded]=\"isEntityExpanded(ea.entity.ID)\"\n >\n <div\n class=\"entity-header\"\n (click)=\"toggleEntityExpansion(ea.entity.ID)\"\n (keydown.enter)=\"toggleEntityExpansion(ea.entity.ID)\"\n (keydown.space)=\"toggleEntityExpansion(ea.entity.ID); $event.preventDefault()\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"'Expand permissions for ' + ea.entity.Name\"\n >\n <div class=\"entity-info\">\n <div class=\"entity-icon-wrapper\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-table\"></i>\n </div>\n <div class=\"entity-details\">\n <h3 class=\"entity-name\">{{ ea.entity.Name }}</h3>\n <p class=\"entity-description\">{{ ea.entity.Description || 'No description available' }}</p>\n </div>\n </div>\n\n <div class=\"entity-meta\">\n <span\n class=\"access-badge\"\n [class]=\"getAccessLevelClass(ea)\"\n [attr.aria-label]=\"'Access level: ' + getAccessLevelLabel(ea)\"\n >\n <i\n [class]=\"getAccessLevelClass(ea) === 'access-public' ? 'fa-solid fa-globe' :\n getAccessLevelClass(ea) === 'access-restricted' ? 'fa-solid fa-lock' :\n 'fa-solid fa-key'\"\n aria-hidden=\"true\"\n ></i>\n {{ getAccessLevelLabel(ea) }}\n </span>\n <div class=\"entity-actions\" (click)=\"$event.stopPropagation()\">\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"editEntityPermissions(ea)\"\n title=\"Edit Permissions\"\n [attr.aria-label]=\"'Edit permissions for ' + ea.entity.Name\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <button\n class=\"expand-btn\"\n [attr.aria-label]=\"(isEntityExpanded(ea.entity.ID) ? 'Collapse' : 'Expand') + ' permissions for ' + ea.entity.Name\"\n >\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n\n @if (isEntityExpanded(ea.entity.ID)) {\n <div class=\"entity-content\" role=\"region\" [attr.aria-label]=\"'Permissions for ' + ea.entity.Name\">\n <!-- Mobile-only actions bar -->\n <div class=\"mobile-actions-bar\" (click)=\"$event.stopPropagation()\">\n <span class=\"access-badge\" [class]=\"getAccessLevelClass(ea)\">\n <i\n [class]=\"getAccessLevelClass(ea) === 'access-public' ? 'fa-solid fa-globe' :\n getAccessLevelClass(ea) === 'access-restricted' ? 'fa-solid fa-lock' :\n 'fa-solid fa-key'\"\n aria-hidden=\"true\"\n ></i>\n {{ getAccessLevelLabel(ea) }}\n </span>\n <div class=\"mobile-action-buttons\">\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"editEntityPermissions(ea)\"\n title=\"Edit Permissions\"\n [attr.aria-label]=\"'Edit permissions for ' + ea.entity.Name\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n <span class=\"btn-label\">Edit</span>\n </button>\n </div>\n </div>\n\n @if (ea.permissions.length > 0) {\n <table class=\"permissions-grid\" role=\"table\" aria-label=\"Role permissions\">\n <thead class=\"permissions-header\" role=\"rowgroup\">\n <tr role=\"row\">\n <th class=\"role-header\" scope=\"col\" role=\"columnheader\">Role</th>\n <th class=\"permission-header\" scope=\"col\" role=\"columnheader\">Create</th>\n <th class=\"permission-header\" scope=\"col\" role=\"columnheader\">Read</th>\n <th class=\"permission-header\" scope=\"col\" role=\"columnheader\">Update</th>\n <th class=\"permission-header\" scope=\"col\" role=\"columnheader\">Delete</th>\n </tr>\n </thead>\n <tbody role=\"rowgroup\">\n @for (roleId of ea.rolePermissions.keys(); track roleId) {\n <tr class=\"permission-row\" role=\"row\">\n <td class=\"role-name\" role=\"cell\">{{ getRoleName(roleId) }}</td>\n <td class=\"permission-cell\" role=\"cell\" [attr.aria-label]=\"'Create: ' + (hasPermission(ea, roleId, 'canCreate') ? 'allowed' : 'denied')\">\n <i\n [class]=\"hasPermission(ea, roleId, 'canCreate') ?\n 'fa-solid fa-check text-success' :\n 'fa-solid fa-times text-muted'\"\n [attr.aria-hidden]=\"true\"\n ></i>\n </td>\n <td class=\"permission-cell\" role=\"cell\" [attr.aria-label]=\"'Read: ' + (hasPermission(ea, roleId, 'canRead') ? 'allowed' : 'denied')\">\n <i\n [class]=\"hasPermission(ea, roleId, 'canRead') ?\n 'fa-solid fa-check text-success' :\n 'fa-solid fa-times text-muted'\"\n [attr.aria-hidden]=\"true\"\n ></i>\n </td>\n <td class=\"permission-cell\" role=\"cell\" [attr.aria-label]=\"'Update: ' + (hasPermission(ea, roleId, 'canUpdate') ? 'allowed' : 'denied')\">\n <i\n [class]=\"hasPermission(ea, roleId, 'canUpdate') ?\n 'fa-solid fa-check text-success' :\n 'fa-solid fa-times text-muted'\"\n [attr.aria-hidden]=\"true\"\n ></i>\n </td>\n <td class=\"permission-cell\" role=\"cell\" [attr.aria-label]=\"'Delete: ' + (hasPermission(ea, roleId, 'canDelete') ? 'allowed' : 'denied')\">\n <i\n [class]=\"hasPermission(ea, roleId, 'canDelete') ?\n 'fa-solid fa-check text-success' :\n 'fa-solid fa-times text-muted'\"\n [attr.aria-hidden]=\"true\"\n ></i>\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <p class=\"no-permissions\">\n @if (ea.isPublic) {\n This entity is publicly accessible by all users.\n } @else {\n No specific role permissions configured. Access is restricted to system administrators.\n }\n </p>\n }\n </div>\n }\n </div>\n }\n </div>\n } @else {\n <!-- Grid View -->\n <div class=\"entities-grid\" role=\"list\" aria-label=\"Entity permissions grid\">\n @for (ea of filteredEntityAccess; track ea.entity.ID) {\n <article\n class=\"entity-grid-card\"\n [class]=\"getAccessLevelClass(ea)\"\n [attr.aria-label]=\"'Entity: ' + ea.entity.Name\"\n >\n <div class=\"grid-card-header\">\n <i class=\"fa-solid fa-table\" aria-hidden=\"true\"></i>\n <button\n mjButton variant=\"flat\" size=\"sm\"\n (click)=\"editEntityPermissions(ea)\"\n [attr.aria-label]=\"'Edit permissions for ' + ea.entity.Name\"\n title=\"Edit Permissions\"\n >\n <i class=\"fa-solid fa-edit\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <h4 class=\"grid-card-title\">{{ ea.entity.Name }}</h4>\n <p class=\"grid-card-description\">{{ ea.entity.Description || 'No description' }}</p>\n <div class=\"grid-card-footer\">\n <span\n class=\"access-label\"\n [attr.aria-label]=\"'Access level: ' + getAccessLevelLabel(ea)\"\n >\n <i\n [class]=\"getAccessLevelClass(ea) === 'access-public' ? 'fa-solid fa-globe' :\n getAccessLevelClass(ea) === 'access-restricted' ? 'fa-solid fa-lock' :\n 'fa-solid fa-key'\"\n aria-hidden=\"true\"\n ></i>\n {{ getAccessLevelLabel(ea) }}\n </span>\n @if (ea.permissions.length > 0) {\n <span\n class=\"permission-count\"\n [attr.aria-label]=\"ea.permissions.length + ' permission' + (ea.permissions.length === 1 ? '' : 's')\"\n >\n {{ ea.permissions.length }} permission{{ ea.permissions.length === 1 ? '' : 's' }}\n </span>\n }\n </div>\n </article>\n }\n </div>\n }\n\n @if (filteredEntityAccess.length === 0) {\n <div class=\"empty-state\" role=\"status\">\n <i class=\"fa-solid fa-shield-alt empty-state-icon\" aria-hidden=\"true\"></i>\n <h3 class=\"empty-text\">No Permissions Found</h3>\n <p class=\"empty-subtext\">Try adjusting your filters or refresh the data.</p>\n <button\n mjButton variant=\"primary\"\n (click)=\"refreshData()\"\n aria-label=\"Refresh permissions data\"\n >\n <i class=\"fa-solid fa-refresh\" aria-hidden=\"true\"></i>\n Refresh\n </button>\n </div>\n }\n </div>\n }\n </div><!-- End Scrollable Content -->\n\n <!-- Permission Edit Dialog -->\n <mj-permission-dialog\n [visible]=\"showPermissionDialog\"\n [data]=\"permissionDialogData\"\n (result)=\"onPermissionDialogResult($event)\"\n ></mj-permission-dialog>\n\n <!-- Mobile Filter Modal -->\n @if (showMobileFilters) {\n <div\n class=\"filter-modal-backdrop\"\n (click)=\"showMobileFilters = false\"\n role=\"presentation\"\n >\n <div\n class=\"filter-modal\"\n (click)=\"$event.stopPropagation()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"filter-modal-title\"\n >\n <div class=\"filter-modal-header\">\n <h3 class=\"filter-modal-title\" id=\"filter-modal-title\">\n <i class=\"fa-solid fa-filter\" aria-hidden=\"true\"></i>\n Filters\n </h3>\n <button\n class=\"filter-modal-close\"\n (click)=\"showMobileFilters = false\"\n aria-label=\"Close filters\"\n >\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <div class=\"filter-modal-body\">\n <div class=\"filter-options-container\">\n <!-- Access Level Filter -->\n <div class=\"filter-group\">\n <h4 class=\"filter-group-label\">Access Level</h4>\n <div class=\"filter-group-options\">\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.accessLevel === 'all'\"\n >\n <input\n type=\"radio\"\n name=\"accessLevel\"\n value=\"all\"\n [checked]=\"filters$.value.accessLevel === 'all'\"\n (change)=\"onAccessLevelChange('all')\"\n />\n <span class=\"filter-option-label\">All Levels</span>\n </label>\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.accessLevel === 'public'\"\n >\n <input\n type=\"radio\"\n name=\"accessLevel\"\n value=\"public\"\n [checked]=\"filters$.value.accessLevel === 'public'\"\n (change)=\"onAccessLevelChange('public')\"\n />\n <span class=\"filter-option-label\">Public Entities</span>\n </label>\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.accessLevel === 'restricted'\"\n >\n <input\n type=\"radio\"\n name=\"accessLevel\"\n value=\"restricted\"\n [checked]=\"filters$.value.accessLevel === 'restricted'\"\n (change)=\"onAccessLevelChange('restricted')\"\n />\n <span class=\"filter-option-label\">Restricted Entities</span>\n </label>\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.accessLevel === 'custom'\"\n >\n <input\n type=\"radio\"\n name=\"accessLevel\"\n value=\"custom\"\n [checked]=\"filters$.value.accessLevel === 'custom'\"\n (change)=\"onAccessLevelChange('custom')\"\n />\n <span class=\"filter-option-label\">Custom Access Entities</span>\n </label>\n </div>\n </div>\n\n <!-- Role Filter -->\n <div class=\"filter-group\">\n <h4 class=\"filter-group-label\">Filter by Role</h4>\n <div class=\"filter-group-options\">\n <label class=\"filter-option\" [class.selected]=\"!filters$.value.roleId\">\n <input\n type=\"radio\"\n name=\"role\"\n value=\"\"\n [checked]=\"!filters$.value.roleId\"\n (change)=\"onRoleFilterChange($event)\"\n />\n <span class=\"filter-option-label\">All Roles</span>\n </label>\n @for (role of roles; track role.ID) {\n <label\n class=\"filter-option\"\n [class.selected]=\"filters$.value.roleId === role.ID\"\n >\n <input\n type=\"radio\"\n name=\"role\"\n [value]=\"role.ID\"\n [checked]=\"filters$.value.roleId === role.ID\"\n (change)=\"onRoleFilterChange($event)\"\n />\n <span class=\"filter-option-label\">{{ role.Name }}</span>\n </label>\n }\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"filter-modal-footer\">\n <button\n mjButton variant=\"primary\"\n (click)=\"showMobileFilters = false\"\n >\n Apply Filters\n </button>\n <button\n mjButton\n (click)=\"showMobileFilters = false\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n", styles: ["/* =============================================================================\n Shared Admin Patterns - MJ Design System\n Common styles shared across all admin settings components.\n Component-specific CSS files override these values where needed.\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Host & Container\n ----------------------------------------------------------------------------- */\n:host {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* -----------------------------------------------------------------------------\n Sticky Header\n ----------------------------------------------------------------------------- */\n.sticky-header {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n/* -----------------------------------------------------------------------------\n Scrollable Content\n ----------------------------------------------------------------------------- */\n.scrollable-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content {\n padding: 2rem 2.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons (In Sticky Header)\n ----------------------------------------------------------------------------- */\n.action-buttons {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .mj-btn-icon-mobile .btn-text {\n display: none;\n }\n\n .mj-btn-icon-mobile {\n padding: 0.5rem 0.75rem;\n min-height: 40px;\n gap: 0;\n border-radius: var(--mj-radius-full);\n }\n\n .mj-btn-icon-mobile i {\n font-size: 1.125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Statistics Cards Grid - Static Display (Non-interactive)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4 {\n gap: 1rem;\n }\n}\n\n/* Static Card - No hover effects */\n.mj-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card {\n padding: 1rem 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Stat Icon Containers\n ----------------------------------------------------------------------------- */\n.stat-icon {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Stat Content Typography\n ----------------------------------------------------------------------------- */\n.stat-content {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content .stat-value {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-value {\n font-size: 2rem;\n }\n}\n\n.stat-content .stat-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-label {\n font-size: 0.8125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Filters Section\n ----------------------------------------------------------------------------- */\n.filters-section {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-filter-buttons .mj-btn {\n border-radius: var(--mj-radius-full);\n}\n\n.mj-filter-buttons .mj-btn-primary {\n background-color: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* -----------------------------------------------------------------------------\n Search Input\n ----------------------------------------------------------------------------- */\n.mj-search {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search .mj-search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-icon {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search .mj-search-input {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search .mj-search-input {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search .mj-search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search .mj-search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search .mj-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search:focus-within .mj-search-icon {\n color: var(--mj-brand-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Content Area\n ----------------------------------------------------------------------------- */\n.content-area {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area {\n padding: 1.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Expand Button\n ----------------------------------------------------------------------------- */\n.expand-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn i {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Status Badge\n ----------------------------------------------------------------------------- */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge i {\n font-size: 0.625rem;\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Actions Bar\n ----------------------------------------------------------------------------- */\n.mobile-actions-bar {\n display: none;\n}\n\n.mobile-action-buttons {\n display: flex;\n gap: 0.5rem;\n}\n\n/* -----------------------------------------------------------------------------\n Empty State\n ----------------------------------------------------------------------------- */\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state .empty-icon {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state .empty-subtext {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Loading State\n ----------------------------------------------------------------------------- */\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n/* -----------------------------------------------------------------------------\n Error State\n ----------------------------------------------------------------------------- */\n.error-container {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container .error-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container .error-icon {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container .error-message {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Dialog\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header .modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header .modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body {\n padding: 1.5rem;\n}\n\n.modal-body p {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body p:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header {\n padding: 1rem;\n }\n\n .modal-header .modal-title {\n font-size: 1.125rem;\n }\n\n .modal-body {\n padding: 1rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n .modal-footer .mj-btn {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* -----------------------------------------------------------------------------\n MJ Button System\n ----------------------------------------------------------------------------- */\n.mj-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 600;\n border: none;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n min-height: 44px;\n}\n\n.mj-btn:disabled {\n opacity: 0.38;\n cursor: not-allowed;\n}\n\n/* Primary Button */\n.mj-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-primary:active:not(:disabled) {\n background: var(--mj-color-brand-400);\n transform: scale(0.98);\n}\n\n/* Secondary Button */\n.mj-btn-secondary {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n}\n\n.mj-btn-secondary:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-btn-secondary:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n border-color: var(--mj-color-brand-700);\n}\n\n/* Ghost Button */\n.mj-btn-ghost {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n\n.mj-btn-ghost:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-btn-ghost:active:not(:disabled) {\n background: var(--mj-color-brand-700);\n}\n\n/* Danger Button */\n.mj-btn-danger {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.mj-btn-danger:hover:not(:disabled) {\n background: var(--mj-color-error-300);\n box-shadow: var(--mj-shadow-md);\n}\n\n.mj-btn-danger:active:not(:disabled) {\n background: var(--mj-color-error-200);\n transform: scale(0.98);\n}\n\n/* Small Button */\n.mj-btn-sm {\n padding: 0.5rem 0.875rem;\n font-size: 0.8125rem;\n min-height: 36px;\n}\n\n/* Icon-only Button */\n.mj-btn-icon-only {\n padding: 0.625rem;\n min-width: 44px;\n min-height: 44px;\n}\n\n/* Icon-mobile Button (text hidden on small screens) */\n.mj-btn-icon-mobile {\n gap: 0.5rem;\n}\n\n.mj-btn-icon-mobile .btn-text {\n display: inline;\n}\n\n/* Ghost Danger Button */\n.mj-btn-ghost.mj-btn-danger {\n background: transparent;\n color: var(--mj-status-error);\n box-shadow: none;\n}\n\n.mj-btn-ghost.mj-btn-danger:hover:not(:disabled) {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n/* -----------------------------------------------------------------------------\n Filter Button (Mobile Only)\n ----------------------------------------------------------------------------- */\n.filter-button {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button i {\n font-size: 1rem;\n}\n\n/* -----------------------------------------------------------------------------\n Filter Modal (Mobile Bottom Sheet)\n ----------------------------------------------------------------------------- */\n.filter-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title i {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer button {\n flex: 1;\n margin: 0;\n}\n\n/* Filter Options Container (Inside Modal) */\n.filter-options-container {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option input[type=\"checkbox\"],\n.filter-option input[type=\"radio\"] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected .filter-option-label {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* -----------------------------------------------------------------------------\n Utility Classes\n ----------------------------------------------------------------------------- */\n.text-danger {\n color: var(--mj-status-error);\n}\n\n.text-warning {\n color: var(--mj-color-warning-500);\n}\n\n.text-success {\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Animations\n ----------------------------------------------------------------------------- */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Focus Indicators\n ----------------------------------------------------------------------------- */\n.mj-search-input:focus-visible,\nbutton:focus-visible,\n.mj-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Reduced Motion\n ----------------------------------------------------------------------------- */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n", "/* =============================================================================\n Entity Permissions Component - Component-Specific Styles\n Shared patterns are in ../shared/styles/_admin-patterns.css\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Container\n ----------------------------------------------------------------------------- */\n.entity-permissions-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n position: relative;\n margin: 0 auto;\n width: 100%;\n background: var(--mj-bg-page);\n}\n\n/* -----------------------------------------------------------------------------\n Sticky Header Override - Has explicit padding values\n ----------------------------------------------------------------------------- */\n.sticky-header {\n padding: 1rem;\n}\n\n@media (min-width: 640px) {\n .sticky-header {\n padding: 1.25rem;\n }\n}\n\n@media (min-width: 768px) {\n .sticky-header {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .sticky-header {\n padding: 1.5rem 2rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Scrollable Content Override - Different breakpoints\n ----------------------------------------------------------------------------- */\n@media (min-width: 640px) {\n .scrollable-content {\n padding: 1.25rem;\n }\n}\n\n@media (min-width: 768px) {\n .scrollable-content {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content {\n padding: 1.5rem 2rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Button Override - min-width and text-decoration\n ----------------------------------------------------------------------------- */\n.mj-btn {\n min-width: 44px;\n text-decoration: none;\n}\n\n/* Ghost Button Override - Different padding */\n.mj-btn-ghost {\n padding: 0.75rem 1rem;\n}\n\n/* Small Button Override - Different min-width */\n.mj-btn-sm {\n min-width: 36px;\n}\n\n/* Icon-mobile Override */\n.mj-btn-icon-mobile {\n padding: 0.75rem 1.5rem;\n}\n\n@media (min-width: 640px) {\n .mj-btn-icon-mobile {\n padding: 0.75rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .mj-btn-icon-mobile .btn-text {\n display: none;\n }\n\n .mj-btn-icon-mobile {\n padding: 0.625rem;\n gap: 0;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons Override - Different layout (space-between with margin)\n ----------------------------------------------------------------------------- */\n.action-buttons {\n justify-content: space-between;\n margin-bottom: 1rem;\n flex-wrap: wrap;\n align-items: center;\n padding: 0;\n background: transparent;\n}\n\n@media (min-width: 768px) {\n .action-buttons {\n margin-bottom: 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Navigation Rail\n ----------------------------------------------------------------------------- */\n@media (max-width: 639px) {\n .sticky-header {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n }\n\n .action-buttons {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n margin-bottom: 0;\n order: 1;\n width: 100%;\n }\n\n .mj-view-toggle {\n flex-shrink: 0;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n padding: 3px;\n gap: 2px;\n }\n\n .mj-view-toggle .mj-btn {\n padding: 0.5rem 0.625rem;\n min-width: 36px;\n min-height: 36px;\n border-radius: var(--mj-radius-md);\n }\n\n .mj-view-toggle .mj-btn.mj-btn-primary {\n box-shadow: none;\n }\n\n .action-buttons > .mj-btn-secondary {\n flex-shrink: 0;\n padding: 0.5rem 0.625rem;\n min-width: 36px;\n min-height: 36px;\n border-radius: var(--mj-radius-lg);\n }\n\n .filters-section {\n order: 2;\n width: 100%;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 0.75rem;\n margin-bottom: 0.5rem;\n border-radius: var(--mj-radius-lg);\n }\n\n .filters-row {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 0.5rem;\n flex-wrap: nowrap;\n }\n\n /* Mobile search container */\n .mobile-search-container {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n flex: 1;\n min-width: 0;\n }\n\n .mj-search {\n flex: 1;\n min-width: 0;\n }\n\n .mj-search .mj-search-input {\n padding: 0.75rem 1rem 0.75rem 2.5rem;\n min-height: 44px;\n font-size: 1rem;\n border-width: 1.5px;\n border-radius: var(--mj-radius-full);\n box-sizing: border-box;\n width: 100%;\n }\n\n .mj-search .mj-search-icon {\n left: 0.875rem;\n font-size: 1rem;\n }\n\n .mj-search .mj-search-input::placeholder {\n font-size: 0.875rem;\n }\n\n /* Hide filter groups on mobile - they go in modal */\n .mj-filter-group {\n display: none !important;\n }\n\n .mj-filter-label {\n display: none;\n }\n\n .mj-filter-select {\n display: none;\n }\n}\n\n/* -----------------------------------------------------------------------------\n View Toggle\n ----------------------------------------------------------------------------- */\n.mj-view-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n.mj-view-toggle .mj-btn {\n padding: 0.5rem 1rem;\n border-radius: var(--mj-radius-full);\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n font-size: 0.875rem;\n font-weight: 500;\n}\n\n.mj-view-toggle .mj-btn:hover:not(:disabled):not(.mj-btn-primary) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-view-toggle .mj-btn.mj-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* -----------------------------------------------------------------------------\n Stats Grid Override - Different layout (margin-based, hidden on mobile)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n margin-bottom: 1rem;\n width: 100%;\n padding: 0;\n background: transparent;\n}\n\n@media (max-width: 639px) {\n .mj-grid-4 {\n display: none !important;\n }\n}\n\n@media (min-width: 640px) {\n .mj-grid-4 {\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n gap: 1.25rem;\n margin-bottom: 1.25rem;\n }\n}\n\n/* Stat Card Override - min-width and no box-shadow */\n.mj-card {\n min-width: 0;\n box-shadow: none;\n}\n\n/* Stat Value Override at 768px - different size */\n@media (min-width: 768px) {\n .stat-content .stat-value {\n font-size: 1.875rem;\n }\n}\n\n/* Stat Icon Override - Component-specific colors */\n.stat-icon-public {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n.stat-icon-restricted {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n}\n\n.stat-icon-permissions {\n background: var(--mj-color-warning-50);\n color: var(--mj-color-warning-700);\n}\n\n/* -----------------------------------------------------------------------------\n Filters Section Override - Different layout (no margin, full width)\n ----------------------------------------------------------------------------- */\n.filters-section {\n border-radius: var(--mj-radius-xl);\n padding: 1rem;\n margin-bottom: 0;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n@media (min-width: 768px) {\n .filters-section {\n padding: 1rem 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .filters-section {\n padding: 1.25rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .filters-row {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .filters-row {\n gap: 1.5rem;\n }\n}\n\n/* Search Input Override at 1024px - different padding */\n@media (min-width: 1024px) {\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3rem;\n }\n\n .mj-search .mj-search-icon {\n left: 1.125rem;\n font-size: 1.125rem;\n }\n}\n\n/* Filter Button Overrides */\n.mj-filter-buttons {\n flex-wrap: wrap;\n}\n\n.mj-filter-buttons .mj-btn {\n padding: 0.5rem 1rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 500;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n}\n\n.mj-filter-buttons .mj-btn:hover:not(:disabled):not(.mj-btn-primary) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.mj-filter-buttons .mj-btn.mj-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n@media (max-width: 639px) {\n .mj-filter-buttons {\n flex-direction: row;\n flex-wrap: wrap;\n }\n\n .mj-filter-buttons .mj-btn {\n flex: 1;\n min-width: calc(50% - 4px);\n padding: 0.5rem 0.75rem;\n font-size: 0.75rem;\n }\n}\n\n/* Filter Label Override */\n.mj-filter-label {\n font-size: 0.8125rem;\n line-height: 1.2;\n}\n\n/* Filter Select Dropdown */\n.mj-filter-select {\n padding: 0.5rem 1rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 500;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n height: 44px;\n min-width: 150px;\n box-sizing: border-box;\n}\n\n.mj-filter-select:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-filter-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n}\n\n@media (max-width: 639px) {\n .mj-filter-select {\n width: 100%;\n }\n}\n\n/* Mobile Search Container (Desktop Default) */\n.mobile-search-container {\n display: contents;\n}\n\n/* Filter Button Badge Override */\n.filter-button .filter-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 0.625rem;\n font-weight: 700;\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n}\n\n/* Loading Container Override - different layout */\n.loading-container {\n min-height: 200px;\n padding: 3rem 1.5rem;\n flex-direction: row;\n}\n\n/* -----------------------------------------------------------------------------\n Content Area Override - Different background and shadow\n ----------------------------------------------------------------------------- */\n.content-area {\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-md);\n padding: 1.25rem;\n}\n\n@media (min-width: 1024px) {\n .content-area {\n padding: 1.75rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Entities List\n ----------------------------------------------------------------------------- */\n.entities-list {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n overflow: visible;\n}\n\n@media (min-width: 768px) {\n .entities-list {\n gap: 1rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Entity Card - Interactive\n ----------------------------------------------------------------------------- */\n.entity-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n overflow: hidden;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-card:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-card.expanded {\n box-shadow: var(--mj-shadow-lg);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-card.expanded .expand-btn i {\n transform: rotate(180deg);\n}\n\n/* Entity Header */\n.entity-header {\n padding: 1rem;\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n background: var(--mj-bg-surface);\n transition: background-color 0.2s ease;\n gap: 0.75rem;\n}\n\n.entity-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .entity-header {\n padding: 1.25rem 1.5rem;\n }\n}\n\n/* Entity Info */\n.entity-info {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n min-width: 0;\n}\n\n@media (min-width: 768px) {\n .entity-info {\n gap: 1rem;\n }\n}\n\n/* Entity Icon Container */\n.entity-icon-wrapper {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n background: var(--mj-color-accent-300);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-brand-primary);\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .entity-icon-wrapper {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n/* Entity Details */\n.entity-details {\n flex: 1;\n min-width: 0;\n}\n\n.entity-details .entity-name {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.25rem 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .entity-details .entity-name {\n font-size: 1.125rem;\n }\n}\n\n.entity-details .entity-description {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .entity-details .entity-description {\n font-size: 0.875rem;\n }\n}\n\n/* Entity Meta */\n.entity-meta {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .entity-meta {\n gap: 0.75rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Access Badges\n ----------------------------------------------------------------------------- */\n.access-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n white-space: nowrap;\n}\n\n@media (min-width: 768px) {\n .access-badge {\n padding: 0.5rem 1rem;\n font-size: 0.8125rem;\n }\n}\n\n.access-badge.access-public {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.access-badge.access-restricted {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.access-badge.access-custom {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n/* Entity Actions - Hide on mobile */\n.entity-actions {\n display: none;\n}\n\n@media (min-width: 640px) {\n .entity-actions {\n display: flex;\n gap: 0.25rem;\n }\n}\n\n@media (max-width: 639px) {\n .entity-meta > .access-badge {\n display: none;\n }\n}\n\n/* Expand Button Override - inline-flex, different transition */\n.expand-btn {\n display: inline-flex;\n}\n\n.expand-btn i {\n transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Entity Content - Expanded Area\n ----------------------------------------------------------------------------- */\n.entity-content {\n padding: 1.25rem;\n background: var(--mj-bg-surface);\n border-top: 1px solid var(--mj-border-default);\n animation: slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@media (min-width: 768px) {\n .entity-content {\n padding: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .entity-content {\n padding: 1.75rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Actions Bar\n ----------------------------------------------------------------------------- */\n@media (max-width: 639px) {\n .mobile-actions-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.75rem;\n margin: -1.25rem -1.25rem 1rem -1.25rem;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .mobile-action-buttons {\n display: flex;\n gap: 0.5rem;\n }\n\n .mobile-action-buttons .mj-btn {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n }\n\n .mobile-action-buttons .btn-label {\n font-size: 0.8125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Permissions Grid (Table)\n ----------------------------------------------------------------------------- */\n.permissions-grid {\n width: 100%;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n border-collapse: collapse;\n}\n\n/* Permissions Header */\n.permissions-header tr {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr 1fr;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-surface-sunken);\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n@media (min-width: 768px) {\n .permissions-header tr {\n padding: 1rem 1.25rem;\n gap: 0.75rem;\n }\n}\n\n@media (max-width: 639px) {\n .permissions-header tr {\n grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;\n padding: 0.625rem 0.75rem;\n font-size: 0.75rem;\n }\n}\n\n/* Permission Row */\n.permission-row {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr 1fr;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-default);\n transition: background-color 0.2s ease;\n}\n\n.permission-row:hover {\n background: var(--mj-bg-surface);\n}\n\n.permission-row:last-child {\n border-bottom: none;\n}\n\n@media (min-width: 768px) {\n .permission-row {\n padding: 1rem 1.25rem;\n gap: 0.75rem;\n }\n}\n\n@media (max-width: 639px) {\n .permission-row {\n grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr;\n padding: 0.625rem 0.75rem;\n }\n}\n\n.role-header,\n.permission-header {\n text-align: left;\n}\n\n.permission-header {\n text-align: center;\n}\n\n.role-name {\n font-weight: 500;\n color: var(--mj-text-primary);\n font-size: 0.875rem;\n display: flex;\n align-items: center;\n}\n\n@media (max-width: 639px) {\n .role-name {\n font-size: 0.75rem;\n }\n}\n\n.permission-cell {\n text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Success text */\n.text-success {\n color: var(--mj-status-success);\n}\n\n.text-muted {\n color: var(--mj-color-neutral-400);\n opacity: 0.6;\n}\n\n.no-permissions {\n color: var(--mj-text-secondary);\n font-size: 0.875rem;\n margin: 0;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n text-align: center;\n}\n\n/* -----------------------------------------------------------------------------\n Entities Grid (Grid View)\n ----------------------------------------------------------------------------- */\n.entities-grid {\n display: grid;\n gap: 0.75rem;\n grid-template-columns: 1fr;\n}\n\n@media (min-width: 640px) {\n .entities-grid {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .entities-grid {\n gap: 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .entities-grid {\n grid-template-columns: repeat(3, 1fr);\n gap: 1.5rem;\n }\n}\n\n/* Entity Grid Card */\n.entity-grid-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-xl);\n padding: 1.25rem;\n position: relative;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.entity-grid-card:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-brand-primary);\n}\n\n.entity-grid-card.access-public {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.entity-grid-card.access-restricted {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.entity-grid-card.access-custom {\n border-left: 4px solid var(--mj-color-warning-500);\n}\n\n@media (min-width: 768px) {\n .entity-grid-card {\n padding: 1.5rem;\n }\n}\n\n/* Grid Card Header */\n.grid-card-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 0.75rem;\n font-size: 1.5rem;\n color: var(--mj-brand-primary);\n}\n\n@media (min-width: 768px) {\n .grid-card-header {\n margin-bottom: 1rem;\n }\n}\n\n/* Grid Card Title */\n.grid-card-title {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n@media (min-width: 768px) {\n .grid-card-title {\n font-size: 1.125rem;\n }\n}\n\n/* Grid Card Description */\n.grid-card-description {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0 0 0.75rem 0;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n@media (min-width: 768px) {\n .grid-card-description {\n font-size: 0.875rem;\n margin: 0 0 1rem 0;\n }\n}\n\n/* Grid Card Footer */\n.grid-card-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n}\n\n/* Access Label */\n.access-label {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n font-weight: 500;\n}\n\n.permission-count {\n color: var(--mj-text-secondary);\n}\n\n/* -----------------------------------------------------------------------------\n Empty State Override - flex layout with gap\n ----------------------------------------------------------------------------- */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n@media (min-width: 768px) {\n .empty-state {\n padding: 5rem 2.5rem;\n }\n}\n\n.empty-state .empty-state-icon {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 0.5rem;\n}\n\n/* Error Container Override - flex layout with min-height */\n.error-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n}\n\n@media (min-width: 768px) {\n .error-container {\n padding: 5rem 2.5rem;\n }\n}\n\n.error-container .error-icon {\n margin-bottom: 0.5rem;\n}\n\n/* slideDown Override - uses max-height instead of translateY */\n@keyframes slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 800px;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Very Small Mobile (< 375px)\n ----------------------------------------------------------------------------- */\n@media (max-width: 374px) {\n .filters-section {\n padding: 0.5rem;\n margin-bottom: 0.375rem;\n }\n\n .filters-row {\n gap: 0.375rem;\n }\n\n .mobile-search-container {\n gap: 0.375rem;\n }\n\n .mj-search .mj-search-input {\n padding: 0.625rem 0.75rem 0.625rem 2.25rem;\n font-size: 0.875rem;\n }\n\n .mj-search .mj-search-icon {\n left: 0.75rem;\n font-size: 0.875rem;\n }\n\n .filter-button {\n padding: 0.625rem;\n min-width: 40px;\n flex-shrink: 0;\n }\n\n .filter-button span {\n display: none;\n }\n\n .filter-modal-header {\n padding: 1rem 1.25rem;\n }\n\n .filter-modal-body {\n padding: 1.25rem;\n }\n\n .filter-modal-footer {\n padding: 1rem 1.25rem;\n }\n}\n"] }]
|
|
839
840
|
}], () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }], null); })();
|
|
840
841
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityPermissionsComponent, { className: "EntityPermissionsComponent", filePath: "src/lib/entity-permissions/entity-permissions.component.ts", lineNumber: 49 }); })();
|
|
841
842
|
//# sourceMappingURL=entity-permissions.component.js.map
|