RSS Git Download  Clone
Raw Blame History 51kB 1501 lines
// P3X Redis UI — Angular Material Theme Application
//
// Each theme has 3 sub-themes matching the AngularJS architecture:
//   - Layout:  toolbar, header, footer → scoped under .p3xr-mat-layout
//   - Main:    content area           → scoped under body.p3xr-mat-theme-{name}
//   - Common:  status indicators      → scoped under .p3xr-mat-common
//
// IMPORTANT: Dark themes come FIRST, light themes come LAST.
// CSS ordering matters — when switching from dark to light, the light theme's
// CSS variables must override the dark theme's. Since body.class selectors have
// equal specificity, the LATER rule in the file wins.
//
// During hybrid mode, these only affect Angular (mat-*) components.
// AngularJS (md-*) components continue using their own theme system.

@use '@angular/material' as mat;
@use 'theme-definitions' as defs;
@use 'theme-custom';

// Angular Material core styles (typography, ripple, etc.) — applied once globally
@include mat.core();

// ============================================================================
// Default theme (Enterprise — light) applied at root level
// ============================================================================
:root {
  @include mat.all-component-themes(defs.$p3xr-theme-enterprise);
}

// Light theme M3 surface neutralization is at the END of the file (after all per-theme
// blocks) so it wins the CSS cascade. See the body.p3xr-theme-light block at the bottom.

// ============================================================================
// DARK THEMES FIRST (so light themes can override when switching)
// ============================================================================

body.p3xr-mat-theme-dark {
  @include mat.all-component-colors(defs.$p3xr-theme-dark);

  .p3xr-mat-layout {
    @include mat.toolbar-color(defs.$p3xr-theme-dark-layout);
    @include mat.button-color(defs.$p3xr-theme-dark-layout);
    @include mat.icon-button-color(defs.$p3xr-theme-dark-layout);
    @include mat.menu-color(defs.$p3xr-theme-dark-layout);
  }

  .p3xr-mat-common {
    @include mat.button-color(defs.$p3xr-theme-dark-common);
    @include mat.icon-color(defs.$p3xr-theme-dark-common);
  }
}

body.p3xr-mat-theme-dark-neu {
  @include mat.all-component-colors(defs.$p3xr-theme-dark-neu);

  .p3xr-mat-layout {
    @include mat.toolbar-color(defs.$p3xr-theme-dark-neu-layout);
    @include mat.button-color(defs.$p3xr-theme-dark-neu-layout);
    @include mat.icon-button-color(defs.$p3xr-theme-dark-neu-layout);
    @include mat.menu-color(defs.$p3xr-theme-dark-neu-layout);
  }

  .p3xr-mat-common {
    @include mat.button-color(defs.$p3xr-theme-dark-neu-common);
    @include mat.icon-color(defs.$p3xr-theme-dark-neu-common);
  }
}

body.p3xr-mat-theme-darko-bluo {
  @include mat.all-component-colors(defs.$p3xr-theme-darko-bluo);

  .p3xr-mat-layout {
    @include mat.toolbar-color(defs.$p3xr-theme-darko-bluo-layout);
    @include mat.button-color(defs.$p3xr-theme-darko-bluo-layout);
    @include mat.icon-button-color(defs.$p3xr-theme-darko-bluo-layout);
    @include mat.menu-color(defs.$p3xr-theme-darko-bluo-layout);
  }

  .p3xr-mat-common {
    @include mat.button-color(defs.$p3xr-theme-darko-bluo-common);
    @include mat.icon-color(defs.$p3xr-theme-darko-bluo-common);
  }
}

body.p3xr-mat-theme-matrix {
  @include mat.all-component-colors(defs.$p3xr-theme-matrix);

  .p3xr-mat-layout {
    @include mat.toolbar-color(defs.$p3xr-theme-matrix-layout);
    @include mat.button-color(defs.$p3xr-theme-matrix-layout);
    @include mat.icon-button-color(defs.$p3xr-theme-matrix-layout);
    @include mat.menu-color(defs.$p3xr-theme-matrix-layout);
  }

  .p3xr-mat-common {
    @include mat.button-color(defs.$p3xr-theme-matrix-common);
    @include mat.icon-color(defs.$p3xr-theme-matrix-common);
  }
}

// ============================================================================
// LIGHT THEMES LAST (override dark theme CSS variables on switch)
// ============================================================================

body.p3xr-mat-theme-light {
  @include mat.all-component-colors(defs.$p3xr-theme-light);

  .p3xr-mat-layout {
    @include mat.toolbar-color(defs.$p3xr-theme-light-layout);
    @include mat.button-color(defs.$p3xr-theme-light-layout);
    @include mat.icon-button-color(defs.$p3xr-theme-light-layout);
    @include mat.menu-color(defs.$p3xr-theme-light-layout);
  }

  .p3xr-mat-common {
    @include mat.button-color(defs.$p3xr-theme-light-common);
    @include mat.icon-color(defs.$p3xr-theme-light-common);
  }
}

body.p3xr-mat-theme-enterprise {
  @include mat.all-component-colors(defs.$p3xr-theme-enterprise);

  .p3xr-mat-layout {
    @include mat.toolbar-color(defs.$p3xr-theme-enterprise-layout);
    @include mat.button-color(defs.$p3xr-theme-enterprise-layout);
    @include mat.icon-button-color(defs.$p3xr-theme-enterprise-layout);
    @include mat.menu-color(defs.$p3xr-theme-enterprise-layout);
  }

  .p3xr-mat-common {
    @include mat.button-color(defs.$p3xr-theme-enterprise-common);
    @include mat.icon-color(defs.$p3xr-theme-enterprise-common);
  }
}

body.p3xr-mat-theme-redis {
  @include mat.all-component-colors(defs.$p3xr-theme-redis);

  .p3xr-mat-layout {
    @include mat.toolbar-color(defs.$p3xr-theme-redis-layout);
    @include mat.button-color(defs.$p3xr-theme-redis-layout);
    @include mat.icon-button-color(defs.$p3xr-theme-redis-layout);
    @include mat.menu-color(defs.$p3xr-theme-redis-layout);
  }

  .p3xr-mat-common {
    @include mat.button-color(defs.$p3xr-theme-redis-common);
    @include mat.icon-color(defs.$p3xr-theme-redis-common);
  }
}

// ============================================================================
// Shared app-level styles consuming CSS custom properties
// ============================================================================

[data-p3xr-tree-key]:hover .p3xr-database-tree-node-label {
  background-color: var(--p3xr-hover-bg);
}

.p3xr-content-border {
  border-left: 1px solid var(--p3xr-content-border-color);
  border-right: 1px solid var(--p3xr-content-border-color);
  border-bottom: 1px solid var(--p3xr-content-border-color);
}

.p3xr-content-border-fixed {
  border-left: 1px solid var(--p3xr-border-color);
  border-right: 1px solid var(--p3xr-border-color);
  border-bottom: 1px solid var(--p3xr-border-color);
}

.p3xr-content-border-toolbar {
  border-left: 1px solid var(--p3xr-border-color);
  border-right: 1px solid var(--p3xr-border-color);
  border-top: 1px solid var(--p3xr-border-color);
}

.p3xr-list-key-odd-item {
  background-color: var(--p3xr-list-odd-bg);
}

.p3xr-list-key-item {
  border-bottom: 1px solid var(--p3xr-list-border);
}

input:-webkit-autofill,
input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 50px var(--p3xr-autofill-bg) inset !important;
  -webkit-text-fill-color: var(--p3xr-autofill-color) !important;
}

fieldset {
  border-color: var(--p3xr-fieldset-border);
}

.p3xr-md-menu-item-selected,
.p3xr-mat-menu-item-selected {
  background-color: var(--p3xr-menu-selected-bg) !important;
}

.p3xr-language-highlighted {
  background-color: var(--mat-menu-item-hover-state-layer-color, rgba(0, 0, 0, 0.04)) !important;
}

.p3xr-connection-group-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  font-weight: 700;
  font-size: 13px;
  opacity: 0.8;
  background: var(--p3xr-list-odd-bg);
  border-bottom: 1px solid var(--p3xr-list-border);
  cursor: pointer;
  user-select: none;
}
.p3xr-connection-group-header:hover {
  opacity: 1;
  background: var(--p3xr-hover-bg);
}

.p3xr-language-menu {
  min-width: 320px !important;
  max-height: 400px !important;

  .mat-mdc-menu-content {
    padding-top: 0;
  }
}

.p3xr-language-search-container {
  padding: 8px 0;
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--mat-menu-container-color, var(--mat-app-surface));
}

.p3xr-language-search-input {
  display: block;
  width: calc(100% - 20px);
  margin: 0 auto;
  padding: 8px;
  border: 2px solid var(--p3xr-input-border-color, var(--p3xr-border-color, rgba(0, 0, 0, 0.12)));
  border-radius: 4px;
  font-size: 14px;
  background: var(--p3xr-input-bg, transparent);
  color: var(--p3xr-input-color, inherit);
  outline: none;
  box-sizing: border-box;

  &:focus {
    border-width: 3px;
    border-color: var(--p3xr-input-border-color, var(--p3xr-border-color, #1976d2));
  }

  &::placeholder {
    color: var(--mat-app-text-color, rgba(0, 0, 0, 0.38));
    opacity: 0.5;
  }
}

.p3xr-command-palette-panel .mat-mdc-dialog-container .mdc-dialog__surface {
  padding: 0 !important;
}

json-tree .key {
  color: var(--p3xr-json-key-color);
  font-weight: bold;
}

// Global button color classes — uses correct Angular Material CSS variable names
// mat-flat-button uses: background-color: var(--mat-button-filled-container-color, var(--mat-sys-primary))
.btn-primary {
  --mdc-filled-button-container-color: var(--p3xr-btn-primary-bg) !important;
  --mdc-filled-button-label-text-color: var(--p3xr-btn-primary-color) !important;
  --mdc-protected-button-container-color: var(--p3xr-btn-primary-bg) !important;
  --mdc-protected-button-label-text-color: var(--p3xr-btn-primary-color) !important;
  --mat-button-filled-container-color: var(--p3xr-btn-primary-bg) !important;
  --mat-button-filled-label-text-color: var(--p3xr-btn-primary-color) !important;
  --mat-button-protected-container-color: var(--p3xr-btn-primary-bg) !important;
  --mat-button-protected-label-text-color: var(--p3xr-btn-primary-color) !important;
  --mat-fab-container-color: var(--p3xr-btn-primary-bg) !important;
  --mat-fab-foreground-color: var(--p3xr-btn-primary-color) !important;
  --mat-fab-small-container-color: var(--p3xr-btn-primary-bg) !important;
  --mat-fab-small-foreground-color: var(--p3xr-btn-primary-color) !important;
  color: var(--p3xr-btn-primary-color) !important;
}
.btn-accent {
  --mdc-filled-button-container-color: var(--p3xr-btn-accent-bg) !important;
  --mdc-filled-button-label-text-color: var(--p3xr-btn-accent-color) !important;
  --mdc-protected-button-container-color: var(--p3xr-btn-accent-bg) !important;
  --mdc-protected-button-label-text-color: var(--p3xr-btn-accent-color) !important;
  --mat-button-filled-container-color: var(--p3xr-btn-accent-bg) !important;
  --mat-button-filled-label-text-color: var(--p3xr-btn-accent-color) !important;
  --mat-button-protected-container-color: var(--p3xr-btn-accent-bg) !important;
  --mat-button-protected-label-text-color: var(--p3xr-btn-accent-color) !important;
  --mat-fab-container-color: var(--p3xr-btn-accent-bg) !important;
  --mat-fab-foreground-color: var(--p3xr-btn-accent-color) !important;
  --mat-fab-small-container-color: var(--p3xr-btn-accent-bg) !important;
  --mat-fab-small-foreground-color: var(--p3xr-btn-accent-color) !important;
  color: var(--p3xr-btn-accent-color) !important;
}
.btn-warn {
  --mdc-filled-button-container-color: var(--p3xr-btn-warn-bg) !important;
  --mdc-filled-button-label-text-color: var(--p3xr-btn-warn-color) !important;
  --mdc-protected-button-container-color: var(--p3xr-btn-warn-bg) !important;
  --mdc-protected-button-label-text-color: var(--p3xr-btn-warn-color) !important;
  --mat-button-filled-container-color: var(--p3xr-btn-warn-bg) !important;
  --mat-button-filled-label-text-color: var(--p3xr-btn-warn-color) !important;
  --mat-button-protected-container-color: var(--p3xr-btn-warn-bg) !important;
  --mat-button-protected-label-text-color: var(--p3xr-btn-warn-color) !important;
  --mat-fab-container-color: var(--p3xr-btn-warn-bg) !important;
  --mat-fab-foreground-color: var(--p3xr-btn-warn-color) !important;
  --mat-fab-small-container-color: var(--p3xr-btn-warn-bg) !important;
  --mat-fab-small-foreground-color: var(--p3xr-btn-warn-color) !important;
  color: var(--p3xr-btn-warn-color) !important;
}

.btn-primary,
.btn-primary .mdc-button__label,
.btn-primary mat-icon,
.btn-primary i {
  color: var(--p3xr-btn-primary-color) !important;
}

.btn-accent,
.btn-accent .mdc-button__label,
.btn-accent mat-icon,
.btn-accent i {
  color: var(--p3xr-btn-accent-color) !important;
}

.btn-warn,
.btn-warn .mdc-button__label,
.btn-warn mat-icon,
.btn-warn i {
  color: var(--p3xr-btn-warn-color) !important;
}

// ============================================================================
// Accordion content
// ============================================================================
.p3xr-accordion-content {
  background-color: var(--p3xr-content-bg, #fafafa);
  color: var(--mat-app-text-color, inherit);
  overflow: visible;
  padding: 0;
}

// ============================================================================
// Buttons — match AngularJS Material md-button md-raised
// Production: height 36px, padding 0 6px, border-radius 4px, uppercase
// ============================================================================
// AngularJS md-button.md-raised: padding 0 6px, margin 6px 8px, min-width 88px, min-height 36px
// AngularJS md-button.md-raised styling for content-area buttons.
.mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base):not(.mat-mdc-snack-bar-action) {
  text-transform: uppercase !important;
  letter-spacing: 0.089em !important;
  border-radius: 4px !important;
  padding: 0 6px !important;
  min-width: 88px !important;
  height: 36px !important;
  line-height: 36px !important;
  margin: 6px 8px !important;
  font-size: 14px !important;
  // Narrower gap between icon and text than Google M3 default
  gap: 3px !important;
  // Match toolbar header/footer letter-spacing
  letter-spacing: 0.1px !important;
}

// Dialog content action buttons: match footer button (p3xr-dialog-actions) padding.
// Must beat global .mat-mdc-button-base:not():not() specificity (0,3,0).
// Uses symmetric padding + justify-content:center so icons are centered in both
// icon+text and icon-only states.
// Wide: icon + text → asymmetric padding matching footer (10px left, 8px right)
// Narrow: icon only → min-width 48px matching footer CANCEL, centered
.p3xr-action-btn.mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) {
  padding-left: 10px !important;
  padding-right: 8px !important;
  margin: 0 4px !important;
  min-width: 48px !important;
  letter-spacing: 0.01em !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
}

.p3xr-action-btn.mat-mdc-button-base mat-icon,
.p3xr-action-btn.mat-mdc-button-base .mat-icon,
.p3xr-action-btn.mat-mdc-button-base i {
  margin-left: 0 !important;
  margin-right: 4px !important;
}

.p3xr-action-btn.mat-mdc-button-base .mdc-button__label {
  display: inline !important;
  gap: 0 !important;
  letter-spacing: inherit !important;
}
.mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base):not(.mat-mdc-snack-bar-action) .mdc-button__label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base):not(.mat-mdc-snack-bar-action) .mdc-button__label > mat-icon,
.mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base):not(.mat-mdc-snack-bar-action) .mdc-button__label > i {
  flex-shrink: 0;
}
.mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base):not(.mat-mdc-snack-bar-action) .mdc-button__ripple {
  border-radius: 4px !important;
}

// Normalize Font Awesome button icons to the same painted size as Material's 24px icons.
// Font Awesome ships a visibly larger glyph inside the same 24px box, so normalize the
// pseudo-element instead of only sizing the outer <i>.
.mat-mdc-button-base i.fa,
.mat-mdc-button-base i.fas,
.mat-mdc-button-base i.far,
.mat-mdc-button-base i.fab {
  transform: none !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 24px !important;
  height: 24px !important;
  line-height: 24px !important;
  font-size: 24px !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

.mat-mdc-button-base i.fa::before,
.mat-mdc-button-base i.fas::before,
.mat-mdc-button-base i.far::before,
.mat-mdc-button-base i.fab::before {
  display: block !important;
  font-size: 15px !important;
  line-height: 15px !important;
  transform: none !important;
}

// Settings page connection actions should match the original AngularJS md-button box model.
.p3xr-connection-item .btn-primary,
.p3xr-connection-item .btn-accent,
.p3xr-connection-item .btn-warn {
  min-width: auto !important;
  padding-left: 8px !important;
  padding-right: 8px !important;
  letter-spacing: 0.01em !important;
}

.p3xr-connection-item .btn-primary .mdc-button__label,
.p3xr-connection-item .btn-accent .mdc-button__label,
.p3xr-connection-item .btn-warn .mdc-button__label {
  display: inline !important;
  gap: 0 !important;
  letter-spacing: inherit !important;
}

.p3xr-connection-item .btn-primary mat-icon,
.p3xr-connection-item .btn-accent mat-icon,
.p3xr-connection-item .btn-warn mat-icon {
  margin-left: 0 !important;
  margin-right: 0 !important;
  width: 24px !important;
  height: 24px !important;
  font-size: 24px !important;
}

.p3xr-connection-item .btn-primary:not([aria-label]) mat-icon,
.p3xr-connection-item .btn-accent:not([aria-label]) mat-icon,
.p3xr-connection-item .btn-warn:not([aria-label]) mat-icon,
.p3xr-connection-item .btn-primary:not([aria-label]) i,
.p3xr-connection-item .btn-accent:not([aria-label]) i,
.p3xr-connection-item .btn-warn:not([aria-label]) i {
  margin-right: 3px !important;
}

// Standalone p3xr-ng-button should match the original AngularJS md-button:
// min-width: 0, horizontal padding: 8px, theme-aware black/white foreground.
p3xr-ng-button .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) {
  min-width: 0 !important;
  padding-left: 8px !important;
  padding-right: 8px !important;
  color: var(--p3xr-plain-button-color) !important;
}

p3xr-ng-button .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) mat-icon,
p3xr-ng-button .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) i,
p3xr-ng-button .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) .mdc-button__label {
  color: inherit !important;
}

// Accordion toolbar: buttons, icons, text use accordion color (md-primary hue-1, always dark-on-light)
.p3xr-accordion-toolbar .p3xr-accordion-title,
.p3xr-accordion-toolbar .p3xr-accordion-actions {
  color: var(--p3xr-accordion-color) !important;
}

.p3xr-accordion-toolbar .mat-mdc-icon-button,
.p3xr-accordion-toolbar .mat-mdc-icon-button mat-icon,
.p3xr-accordion-toolbar p3xr-ng-button .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base),
.p3xr-accordion-toolbar p3xr-ng-button .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) .mdc-button__label,
.p3xr-accordion-toolbar p3xr-ng-button .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) mat-icon,
.p3xr-accordion-toolbar p3xr-ng-button .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) i {
  color: var(--p3xr-accordion-color) !important;
}

.p3xr-accordion-toolbar .mat-mdc-button-base,
.p3xr-accordion-toolbar .mat-mdc-icon-button,
.p3xr-accordion-toolbar mat-icon,
.p3xr-accordion-toolbar .mat-mdc-button-base .mdc-button__label {
  color: var(--p3xr-accordion-color) !important;
}

// Version/SNAPSHOT label overlaying the header toolbar — must match toolbar text color.
// AngularJS used md-colors="{ color: 'background-A100' }" (white for most themes, grey-900 for Matrix).
#p3xr-layout-header-version {
  color: var(--p3xr-toolbar-color) !important;
}

body.p3xr-mat-theme-matrix #p3xr-layout-header-version {
  color: #212121 !important; // grey-900 — AngularJS used getVersionColor() → 'grey-900' for Matrix
}

// Matrix: bright green toolbar needs dark hover (white is invisible on #76ff03)
body.p3xr-mat-theme-matrix mat-toolbar.p3xr-mat-layout .mat-mdc-button-base:not(.mat-mdc-fab-base):hover {
  background-color: rgba(0, 0, 0, 0.1) !important;
}

// Matrix: darken dialog footer — bright #76ff03 is too intense as a footer bg
body.p3xr-mat-theme-matrix .p3xr-dialog-actions {
  background-color: #0a2e0d !important; // near-black green
}

// Accordion toolbar: hue-1 color from Layout sub-theme (section headers in content area).
// Uses mat-toolbar.class for higher specificity over mat.all-component-colors() output.
mat-toolbar.p3xr-accordion-toolbar {
  background-color: var(--p3xr-accordion-bg) !important;
  color: var(--p3xr-accordion-color) !important;
}
// Force all children in accordion toolbar to inherit accordion color
mat-toolbar.p3xr-accordion-toolbar * {
  color: inherit;
}
mat-toolbar.p3xr-accordion-toolbar .mat-mdc-select,
mat-toolbar.p3xr-accordion-toolbar .mat-mdc-select-value,
mat-toolbar.p3xr-accordion-toolbar .mat-mdc-select-arrow,
mat-toolbar.p3xr-accordion-toolbar .mat-mdc-form-field,
mat-toolbar.p3xr-accordion-toolbar .mdc-text-field,
mat-toolbar.p3xr-accordion-toolbar .mat-mdc-floating-label,
mat-toolbar.p3xr-accordion-toolbar mat-icon,
mat-toolbar.p3xr-accordion-toolbar span,
mat-toolbar.p3xr-accordion-toolbar a {
  color: var(--p3xr-accordion-color) !important;
}

// Layout toolbar: exact colors matching AngularJS md-toolbar with Layout sub-theme.
// The mat.toolbar-color() mixin above applies M3 palette colors which approximate
// but don't match the AngularJS Material M1 colors. These CSS custom properties
// (defined per-theme in _theme-custom.scss) provide the exact hex values from the
// original AngularJS palette definitions.
mat-toolbar.p3xr-mat-layout {
  background-color: var(--p3xr-toolbar-bg) !important;
  color: var(--p3xr-toolbar-color) !important;
  // Match AngularJS Material md-toolbar font-size (M3 default is 22px)
  font-size: 20px !important;
  // Override Angular Material button letter-spacing CSS variables to match M1 (~0.1px)
  --mdc-text-button-label-text-tracking: 0.1px !important;
  --mdc-protected-button-label-text-tracking: 0.1px !important;
  --mat-toolbar-title-text-tracking: normal !important;
  // Lock toolbar to 48px at all breakpoints (AM default is 64px desktop / 56px mobile)
  --mat-toolbar-standard-height: 48px;
  --mat-toolbar-mobile-height: 48px;
}

// Header toolbar elevation: Material elevation 8dp
#p3xr-layout-header-container mat-toolbar.p3xr-mat-layout {
  box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2),
              0px 8px 10px 1px rgba(0, 0, 0, 0.14),
              0px 3px 14px 2px rgba(0, 0, 0, 0.12) !important;
}

// Footer toolbar elevation: Material elevation 8dp (upward)
#p3xr-layout-footer-container mat-toolbar.p3xr-mat-layout {
  box-shadow: 0px -5px 5px -3px rgba(0, 0, 0, 0.2),
              0px -8px 10px 1px rgba(0, 0, 0, 0.14),
              0px -3px 14px 2px rgba(0, 0, 0, 0.12) !important;
}

// Buttons inside layout toolbars: match AngularJS md-button styling.
// Uses :not() pseudo-classes to beat the global .mat-mdc-button-base:not():not()
// rule (specificity 0,3,0) that sets letter-spacing: 0.089em.
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base:not(.mat-mdc-fab-base) {
  color: inherit !important;
  letter-spacing: 0.1px !important;
  text-transform: uppercase !important;
  height: 36px !important;
  min-height: 36px !important;
  min-width: auto !important;
  // Narrower padding than production to save space in footer with many buttons
  padding: 0px 4px !important;
  margin: 0px 4px !important;
  // Center icon when button collapses to icon-only
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  // Hover: lighten on dark toolbar background (matches AngularJS md-button-dark-hover-fix).
  // Uses white alpha since toolbar bg is dark in most themes.
  // Matrix theme overrides below with dark hover for its bright green toolbar.
  &:hover {
    background-color: rgba(255, 255, 255, 0.15) !important;
  }
}

// All text-bearing children inside layout toolbar buttons
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base:not(.mat-mdc-fab-base) *,
mat-toolbar.p3xr-mat-layout .mdc-button__label,
mat-toolbar.p3xr-mat-layout span {
  color: inherit !important;
  letter-spacing: 0.1px !important;
}

// Uniform icon-to-text gap: zero out Angular Material's internal gaps,
// then use explicit margin-right on icons for consistent 4px gap.
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base:not(.mat-mdc-fab-base) {
  gap: 0 !important;
}
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base:not(.mat-mdc-fab-base) .mdc-button__label {
  gap: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  margin-left: 0 !important;
}
// Same margin-right on both icon types for uniform gap.
// When icon is :last-child (no text label visible), margin is 0 for square icon-only buttons.
mat-toolbar.p3xr-mat-layout mat-icon,
mat-toolbar.p3xr-mat-layout i.fa,
mat-toolbar.p3xr-mat-layout i.fas,
mat-toolbar.p3xr-mat-layout i.fab {
  margin-right: 4px !important;
  margin-left: 0 !important;
}
mat-toolbar.p3xr-mat-layout mat-icon:last-child,
mat-toolbar.p3xr-mat-layout i.fa:last-child,
mat-toolbar.p3xr-mat-layout i.fas:last-child,
mat-toolbar.p3xr-mat-layout i.fab:last-child {
  margin-right: 0 !important;
}

// All icons inside layout toolbars: uniform 24px matching AngularJS md-icon size
mat-toolbar.p3xr-mat-layout mat-icon {
  font-size: 24px !important;
  width: 24px !important;
  height: 24px !important;
  color: inherit !important;
}

// FA icons in layout toolbars: 24px matching Material icons.
// Must override the global .mat-mdc-button-base i.fa::before rule (specificity 0,2,1)
// which forces FA glyphs to 15px — so we use .mat-mdc-button-base in our selector too.
mat-toolbar.p3xr-mat-layout i.fa,
mat-toolbar.p3xr-mat-layout i.fas,
mat-toolbar.p3xr-mat-layout i.fab {
  font-size: 24px !important;
  line-height: 1 !important;
  vertical-align: middle !important;
  color: inherit !important;
}
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base i.fa::before,
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base i.fas::before,
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base i.far::before,
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base i.fab::before {
  font-size: 24px !important;
  line-height: 24px !important;
}
// fa-power-off and fa-donate glyphs are visually larger than Material icons — scale down to match
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base i.fa-power-off::before,
mat-toolbar.p3xr-mat-layout .mat-mdc-button-base i.fa-donate::before {
  font-size: 21px !important;
  line-height: 24px !important;
}

.p3xr-mat-layout-strong {
  background-color: var(--p3xr-toolbar-strong-bg) !important;
  color: var(--p3xr-toolbar-strong-color) !important;
}

.p3xr-mat-layout-strong .mat-mdc-icon-button,
.p3xr-mat-layout-strong .mat-icon,
.p3xr-mat-layout-strong .mdc-icon-button,
.p3xr-mat-layout-strong .mdc-button__label {
  color: inherit !important;
}

.p3xr-mat-common .btn-primary {
  --mdc-filled-button-container-color: var(--p3xr-common-btn-primary-bg) !important;
  --mdc-filled-button-label-text-color: var(--p3xr-common-btn-primary-color) !important;
  --mdc-protected-button-container-color: var(--p3xr-common-btn-primary-bg) !important;
  --mdc-protected-button-label-text-color: var(--p3xr-common-btn-primary-color) !important;
  --mat-button-filled-container-color: var(--p3xr-common-btn-primary-bg) !important;
  --mat-button-filled-label-text-color: var(--p3xr-common-btn-primary-color) !important;
  --mat-button-protected-container-color: var(--p3xr-common-btn-primary-bg) !important;
  --mat-button-protected-label-text-color: var(--p3xr-common-btn-primary-color) !important;
  color: var(--p3xr-common-btn-primary-color) !important;
}

.p3xr-mat-common .btn-primary .mdc-button__label,
.p3xr-mat-common .btn-primary mat-icon,
.p3xr-mat-common .btn-primary i {
  color: inherit !important;
}

// Accordion toolbar icon buttons must keep the original AngularJS md-icon-button geometry:
// square 40x40, 8px padding, no 88px min-width from the shared raised-button override.
.p3xr-accordion-toolbar .mat-mdc-icon-button {
  min-width: 0 !important;
  width: 40px !important;
  height: 40px !important;
  padding: 8px !important;
  margin: 0 6px !important;
  line-height: 24px !important;
  border-radius: 50% !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  flex: 0 0 40px !important;
}

.p3xr-accordion-toolbar .mat-mdc-icon-button .mat-mdc-button-touch-target {
  width: 40px !important;
  height: 40px !important;
}

.p3xr-accordion-toolbar .mat-mdc-icon-button mat-icon {
  margin: 0 !important;
}

// Accordion toolbar button/icon styling — mirrors the layout toolbar rules above.
// Ensures buttons, icons (Material + FA), and text match the layout footer appearance.
mat-toolbar.p3xr-accordion-toolbar .mat-mdc-button-base:not(.mat-mdc-fab-base) *,
mat-toolbar.p3xr-accordion-toolbar .mdc-button__label,
mat-toolbar.p3xr-accordion-toolbar span {
  color: inherit !important;
  letter-spacing: 0.1px !important;
}
mat-toolbar.p3xr-accordion-toolbar .mat-mdc-button-base:not(.mat-mdc-fab-base) {
  gap: 0 !important;
}
mat-toolbar.p3xr-accordion-toolbar .mat-mdc-button-base:not(.mat-mdc-fab-base) .mdc-button__label {
  gap: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  margin-left: 0 !important;
}
mat-toolbar.p3xr-accordion-toolbar mat-icon,
mat-toolbar.p3xr-accordion-toolbar i.fa,
mat-toolbar.p3xr-accordion-toolbar i.fas,
mat-toolbar.p3xr-accordion-toolbar i.fab {
  margin-right: 4px !important;
  margin-left: 0 !important;
}
mat-toolbar.p3xr-accordion-toolbar mat-icon:last-child,
mat-toolbar.p3xr-accordion-toolbar i.fa:last-child,
mat-toolbar.p3xr-accordion-toolbar i.fas:last-child,
mat-toolbar.p3xr-accordion-toolbar i.fab:last-child {
  margin-right: 0 !important;
}
mat-toolbar.p3xr-accordion-toolbar mat-icon {
  font-size: 24px !important;
  width: 24px !important;
  height: 24px !important;
  color: inherit !important;
}
// FA icons in accordion toolbars: 24px matching Material icons.
// Overrides the global .mat-mdc-button-base rule that forces ::before to 15px.
mat-toolbar.p3xr-accordion-toolbar i.fa,
mat-toolbar.p3xr-accordion-toolbar i.fas,
mat-toolbar.p3xr-accordion-toolbar i.far,
mat-toolbar.p3xr-accordion-toolbar i.fab {
  font-size: 24px !important;
  line-height: 1 !important;
  vertical-align: middle !important;
  color: inherit !important;
}
mat-toolbar.p3xr-accordion-toolbar i.fa::before,
mat-toolbar.p3xr-accordion-toolbar i.fas::before,
mat-toolbar.p3xr-accordion-toolbar i.far::before,
mat-toolbar.p3xr-accordion-toolbar i.fab::before {
  font-size: 24px !important;
  line-height: 24px !important;
}

// Database select dropdown: wider panel, circle indicator, no selection checkmark
.p3xr-database-db-select-container {
  min-width: 120px !important;
}
.p3xr-database-db-select-container .mat-mdc-option {
  color: var(--mat-app-text-color, inherit) !important;
}
.p3xr-database-db-select-container .mat-mdc-option .mat-pseudo-checkbox {
  display: none !important;
}
.p3xr-database-db-select-container .mat-mdc-option .p3xr-db-indicator {
  font-size: 18px !important;
  width: 18px !important;
  height: 18px !important;
  margin-right: 8px !important;
  vertical-align: middle;
  color: var(--mat-app-text-color, inherit) !important;
}

// ============================================================================
// mat-list — match production md-list
// ============================================================================
.mat-mdc-list {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}
.mat-mdc-list-item .mdc-list-item__primary-text {
  font-weight: 400 !important;
  color: inherit !important;
}
.mat-mdc-list-item .p3xr-settings-label {
  font-weight: 500 !important;
}

// ============================================================================
// Hover — only on Redis settings accordion items, not the connections list
// Buttons inside list items keep their own bg on hover
// ============================================================================
.mat-mdc-list-item .mat-mdc-button-base {
  position: relative;
  z-index: 1;
}

// ============================================================================
// Color inheritance fixes for hybrid mode
// ============================================================================
.mat-mdc-card {
  color: var(--mat-app-text-color, inherit);
}

mat-toolbar {
  color: var(--mat-toolbar-container-text-color, inherit);
}

mat-dialog-container {
  color: var(--mat-app-text-color, inherit);
}

// Dialog layout: surface → container → component-host → form → toolbar+content+actions
// The surface constrains the overall height. The content area scrolls.
// Every level in the chain must be flex column with min-height:0 so flex shrinking works.
.cdk-overlay-pane.p3xr-dialog-panel {
  max-height: calc(100vh - 64px) !important;
}

.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-surface {
  border-radius: 4px !important;
  background-color: var(--p3xr-dialog-surface-bg, var(--p3xr-content-bg)) !important;
  box-shadow:
    0 7px 8px -4px rgba(0, 0, 0, 0.2),
    0 13px 19px 2px rgba(0, 0, 0, 0.14),
    0 5px 24px 4px rgba(0, 0, 0, 0.12) !important;
  display: flex !important;
  flex-direction: column !important;
  max-height: inherit !important;
  height: 100% !important;
  overflow: hidden !important;
}

.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-container {
  min-width: 0 !important;
  max-height: inherit !important;
  height: 100% !important;
  display: flex !important;
  flex-direction: column !important;
  overflow: hidden !important;
}

.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-component-host {
  display: flex !important;
  flex: 1 1 auto;
  flex-direction: column !important;
  min-height: 0 !important;
  overflow: hidden !important;
}

.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-component-host > form {
  display: flex !important;
  flex: 1 1 auto;
  flex-direction: column !important;
  min-height: 0 !important;
  overflow: hidden !important;
}

// Toolbar stays fixed at top, actions at bottom, content scrolls in between
.cdk-overlay-pane.p3xr-dialog-panel .p3xr-dialog-toolbar {
  flex: 0 0 auto;
}

.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-component-host > .p3xr-dialog-content,
.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-component-host > form > .p3xr-dialog-content {
  flex: 1 1 auto;
  min-height: 0 !important;
  max-height: none !important;
  overflow-y: auto !important;
  overflow-x: hidden !important;
}

.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-component-host > .p3xr-dialog-content.p3xr-dialog-content-editor,
.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-component-host > form > .p3xr-dialog-content.p3xr-dialog-content-editor {
  overflow: hidden !important;
  max-height: none !important;
  position: relative !important;
}

.cdk-overlay-pane.p3xr-dialog-panel .p3xr-dialog-actions {
  flex: 0 0 auto;
}

.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-component-host > .p3xr-dialog-actions,
.cdk-overlay-pane.p3xr-dialog-panel .mat-mdc-dialog-component-host > form > .p3xr-dialog-actions {
  flex: 0 0 auto;
}

// Snackbar dismiss button: constrain hover to a square (width = height) like an icon button
.mat-mdc-snack-bar-container .mat-mdc-snack-bar-action .mdc-button {
  min-width: 0 !important;
  width: 12px !important;
  height: 12px !important;
  padding: 0 !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
}

.mat-mdc-snack-bar-container .mat-mdc-snack-bar-action .mdc-button .mdc-button__ripple,
.mat-mdc-snack-bar-container .mat-mdc-snack-bar-action .mdc-button .mat-mdc-button-touch-target {
  width: 12px !important;
  height: 12px !important;
  border-radius: 50% !important;
}

.cdk-overlay-backdrop.p3xr-dialog-backdrop {
  background-color: rgba(0, 0, 0, 0.48) !important;
}

html.cdk-global-scrollblock {
  overflow: hidden !important;
}

html.cdk-global-scrollblock body {
  overflow: hidden !important;
}

// TODO: HACK: Angular CDK's BlockScrollStrategy adds the class cdk-global-scrollblock to the
// html element (see @angular/cdk overlay.css: .cdk-global-scrollblock { position: fixed; ... }).
// That makes the html element position:fixed, which in turn affects the body's containing block.
// When html is position:fixed the CDK overlay pane (position:absolute inside the
// position:fixed overlay container) loses its correct containing-block relationship and
// dialog content visually overflows the surface boundary (the "clipping" bug visible
// in tests/screenshots/dialog-no-clipping-scrolled.png).
// Setting the body to position:static cancels that side-effect and the dialog surface
// overflow:hidden clips correctly again.
// The trade-off is that body.style.top = -scrollY set by CDK has no effect on a static
// element, so the page scroll position is not preserved while the dialog is open — which
// is acceptable for this app.
// Remove this override once you understand the root cause and can fix it properly.
html.cdk-global-scrollblock > body {
  position: static !important;
  overflow: hidden !important;
}

body.p3xr-no-animation .cdk-overlay-pane.p3xr-dialog-panel,
body.p3xr-no-animation .cdk-overlay-pane.p3xr-dialog-panel *,
body.p3xr-no-animation .cdk-overlay-backdrop.p3xr-dialog-backdrop,
.cdk-overlay-pane.p3xr-dialog-no-animation,
.cdk-overlay-pane.p3xr-dialog-no-animation *,
.cdk-overlay-backdrop.p3xr-dialog-backdrop-no-animation {
  animation: none !important;
  animation-duration: 0ms !important;
  transition: none !important;
  transition-duration: 0ms !important;
}

.p3xr-dialog-toolbar {
  box-sizing: border-box;
  display: flex !important;
  align-items: center !important;
  height: 48px !important;
  min-height: 48px !important;
  max-height: 48px !important;
  padding: 0 8px !important;
}

.p3xr-dialog-toolbar .mat-mdc-button-base {
  margin: 0 !important;
}

.p3xr-dialog-toolbar [mat-dialog-title] {
  margin: 0 !important;
  padding: 0 !important;
}

.p3xr-dialog-title {
  display: flex !important;
  align-items: center !important;
  flex: 1 1 auto;
  height: 100%;
  line-height: 28px !important;
  min-width: 0;
  margin: 0 !important;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.p3xr-dialog-toolbar .p3xr-dialog-title,
.p3xr-dialog-toolbar [mat-dialog-title],
.p3xr-dialog-toolbar .mat-mdc-dialog-title,
.p3xr-dialog-toolbar .mdc-dialog__title {
  color: inherit !important;
}

.p3xr-dialog-title-with-icon {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.p3xr-dialog-title-with-icon .mat-icon {
  margin: 0 !important;
}

.p3xr-dialog-content {
  display: block;
  padding: 16px !important;
  background-color: var(--p3xr-content-bg) !important;
  color: var(--mat-app-text-color, inherit);
}
// Links inside dialog content must contrast with the content background
.p3xr-dialog-content .p3xr-timestring-link,
.p3xr-dialog-content .p3xr-timestring-link .mdc-button__label {
  color: var(--mat-app-text-color, inherit) !important;
}
// Hint text in dark themes: white with opacity for readability
body.p3xr-theme-dark .mat-mdc-form-field-hint {
  color: rgba(255, 255, 255, 0.7) !important;
}
// Settings page hint text — theme-aware
.p3xr-settings-hint {
  font-size: 12px;
  color: rgba(0, 0, 0, 0.54);
}
body.p3xr-theme-dark .p3xr-settings-hint {
  color: rgba(255, 255, 255, 0.7);
}

.p3xr-dialog-content-mono {
  font-family: 'Roboto Mono', monospace;
}

.p3xr-dialog-actions {
  align-items: center !important;
  box-sizing: border-box;
  justify-content: flex-end !important;
  gap: 8px;
  padding: 8px !important;
  background-color: var(--p3xr-accordion-bg) !important;
}

.p3xr-dialog-actions .mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base),
.p3xr-dialog-actions button.mat-mdc-button-base:not(.mat-mdc-icon-button):not(.mat-mdc-fab-base) {
  margin: 0 !important;
  min-width: 0 !important;
  padding-left: 10px !important;
  padding-right: 8px !important;
  letter-spacing: 0.01em !important;
}

.p3xr-dialog-actions .mat-mdc-button-base .mdc-button__label {
  display: inline !important;
  gap: 0 !important;
  letter-spacing: inherit !important;
}

.p3xr-dialog-actions .mat-mdc-button-base mat-icon,
.p3xr-dialog-actions .mat-mdc-button-base .mat-icon,
.p3xr-dialog-actions .mat-mdc-button-base i,
.p3xr-dialog-actions .mat-mdc-button-base .mdc-button__label > mat-icon,
.p3xr-dialog-actions .mat-mdc-button-base .mdc-button__label > .mat-icon,
.p3xr-dialog-actions .mat-mdc-button-base .mdc-button__label > i {
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  margin-left: 0 !important;
  width: 24px !important;
  height: 24px !important;
  line-height: 24px !important;
  font-size: 24px !important;
  margin-right: 3px !important;
}

.cdk-overlay-pane.p3xr-connection-dialog-panel {
  width: 75vw !important;
  max-width: 75vw !important;
  max-height: calc(100vh - 64px) !important;
}

.p3xr-connection-dialog-panel .mdc-label,
.p3xr-connection-dialog-panel fieldset legend,
.p3xr-connection-dialog-panel .mdc-floating-label {
  font-weight: 700 !important;
}

.p3xr-connection-dialog-panel .mat-mdc-form-field {
  display: block;
}

.p3xr-connection-dialog-panel .p3xr-md-input-container-no-bottom .mat-mdc-form-field-subscript-wrapper {
  display: none !important;
}

.p3xr-connection-dialog-panel .p3xr-md-input-container-bottom-info {
  font-size: 12px;
  margin-top: 0;
}

.cdk-overlay-pane.p3xr-tree-settings-dialog-panel {
  width: 75vw !important;
  max-width: 75vw !important;
  max-height: calc(100vh - 64px) !important;
  --mat-form-field-container-height: 40px;
  --mat-form-field-container-vertical-padding: 8px;
  --mat-form-field-filled-with-label-container-padding-top: 16px;
  --mat-form-field-filled-with-label-container-padding-bottom: 4px;
}


.p3xr-connection-dialog-content,
.p3xr-tree-settings-dialog-content {
  padding: 0 !important;
  background-color: var(--p3xr-content-bg) !important;
  overflow: auto !important;
  min-height: 0 !important;
  max-height: none !important;
}

.p3xr-tree-settings-dialog-content .p3xr-padding {
  padding-top: 26px;
  padding-bottom: 8px;
}

.p3xr-tree-settings-dialog-panel .mdc-label,
.p3xr-tree-settings-dialog-panel fieldset legend,
.p3xr-tree-settings-dialog-panel .mdc-floating-label {
  font-weight: 700 !important;
}

.p3xr-tree-settings-dialog-panel .mat-mdc-form-field {
  display: block;
}

.p3xr-tree-settings-dialog-panel .p3xr-md-input-container-no-bottom .mat-mdc-form-field-subscript-wrapper {
  display: none !important;
}

.p3xr-tree-settings-dialog-panel .p3xr-md-input-container-bottom-info {
  font-size: 12px;
  line-height: normal;
  margin-top: 0;
}

.p3xr-tree-settings-field-block {
  margin-bottom: 21px;
}

.p3xr-tree-settings-field-block-max-keys {
  margin-bottom: 16px;
}

.p3xr-tree-settings-toggle-block,
.p3xr-tree-settings-reduced-functions {
  margin-bottom: 12px;
}

.p3xr-tree-settings-toggle-block {
  margin-bottom: 0;
}

.p3xr-tree-settings-toggle-block-keys-sort {
  margin-bottom: 18px;
}

.p3xr-tree-settings-toggle-block-search-client {
  margin-bottom: 19px;
}

.p3xr-tree-settings-reduced-functions-note,
.p3xr-tree-settings-extra-info {
  margin-top: 8px;
}

.p3xr-tree-settings-message-error {
  color: var(--mat-sys-error, #f44336) !important;
  opacity: 1 !important;
}

.p3xr-tree-settings-toggle-block .mat-mdc-slide-toggle {
  display: block;
  margin: 0 !important;
  max-width: 100%;
}

.p3xr-tree-settings-toggle-block .mdc-form-field {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  white-space: normal !important;
}

.p3xr-tree-settings-toggle-block .mdc-label {
  white-space: normal !important;
  overflow-wrap: anywhere;
}

.p3xr-tree-settings-toggle-block-last {
  margin-bottom: 0;
}

.p3xr-connection-node-add,
.p3xr-connection-node-actions {
  display: inline-flex;
  align-items: center;
}

.p3xr-connection-node-add .mat-mdc-mini-fab,
.p3xr-connection-node-actions .mat-mdc-mini-fab {
  margin: 0 0 0 8px !important;
}

.p3xr-connection-node-actions .mat-mdc-mini-fab:first-child {
  margin-left: 0 !important;
  margin-right: 8px !important;
}

.p3xr-connection-inline-toggles {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  column-gap: 16px;
  row-gap: 8px;
}

.p3xr-connection-inline-toggles .mat-mdc-slide-toggle {
  margin: 0 !important;
  max-width: 100%;
}

.p3xr-connection-inline-toggles .mdc-form-field {
  white-space: normal !important;
}

.p3xr-connection-inline-toggles .mdc-label {
  white-space: normal !important;
  overflow-wrap: anywhere;
}

.p3xr-connection-tls-toggles {
  margin-bottom: 12px;
}

.p3xr-connection-tls-fields {
  padding-top: 0;
}

.p3xr-connection-dialog-panel textarea.mat-mdc-input-element {
  min-height: 30px !important;
  resize: vertical;
}

@media (max-width: 959px) {
  .cdk-overlay-pane.fullscreen-dialog .mat-mdc-dialog-container,
  .cdk-overlay-pane.fullscreen-dialog .mat-mdc-dialog-surface {
    height: 100% !important;
    max-height: 100% !important;
  }

  .cdk-overlay-pane.fullscreen-dialog .mat-mdc-dialog-surface form {
    display: flex !important;
    flex-direction: column !important;
    min-height: 100% !important;
    height: 100% !important;
  }

  .cdk-overlay-pane.fullscreen-dialog .p3xr-dialog-content {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto !important;
  }

  .cdk-overlay-pane.fullscreen-dialog .p3xr-connection-dialog-content {
    max-height: none !important;
  }

  .cdk-overlay-pane.fullscreen-dialog .p3xr-dialog-actions {
    flex: 0 0 auto;
    margin-top: auto;
  }

  .cdk-overlay-pane.p3xr-connection-dialog-panel {
    width: 100vw !important;
    max-width: 100vw !important;
    height: 100vh !important;
    max-height: calc(100vh - 64px) !important;
  }

  .cdk-overlay-pane.p3xr-connection-dialog-panel .mat-mdc-dialog-surface {
    border-radius: 0 !important;
  }

  .cdk-overlay-pane.p3xr-tree-settings-dialog-panel {
    width: 100vw !important;
    max-width: 100vw !important;
    height: 100vh !important;
    max-height: calc(100vh - 64px) !important;
  }

  .cdk-overlay-pane.p3xr-tree-settings-dialog-panel .mat-mdc-dialog-surface {
    border-radius: 0 !important;
  }
}

p3xr-ng-settings .p3xr-settings-pair-row,
p3xr-info .p3xr-settings-pair-row,
p3xr-monitoring .p3xr-settings-pair-row,
p3xr-memory-analysis .p3xr-settings-pair-row,
p3xr-search .p3xr-settings-pair-row {
  display: flex;
  width: 100%;
  gap: 16px;
}

p3xr-ng-settings .p3xr-settings-pair-row,
p3xr-info .p3xr-settings-pair-row,
p3xr-monitoring .p3xr-settings-pair-row,
p3xr-memory-analysis .p3xr-settings-pair-row,
p3xr-search .p3xr-settings-pair-row {
  align-items: center;
}

p3xr-ng-settings .p3xr-settings-row-label,
p3xr-info .p3xr-settings-row-label,
p3xr-monitoring .p3xr-settings-row-label,
p3xr-memory-analysis .p3xr-settings-row-label,
p3xr-search .p3xr-settings-row-label {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 700;
}

p3xr-ng-settings .p3xr-settings-row-value,
p3xr-info .p3xr-settings-row-value,
p3xr-monitoring .p3xr-settings-row-value,
p3xr-memory-analysis .p3xr-settings-row-value,
p3xr-search .p3xr-settings-row-value {
  flex: 0 1 60%;
  min-width: 0;
  text-align: right;
  white-space: normal;
  overflow-wrap: anywhere;
  word-break: break-word;
}

p3xr-ng-settings .p3xr-settings-wrap-text {
  white-space: normal;
  overflow-wrap: anywhere;
  word-break: break-word;
}

// ============================================================================
// Prevent horizontal scrollbar from body during hybrid mode
// ============================================================================
body {
  overflow-x: hidden;
}

// ============================================================================
// Neutralize Angular Material primary-tinted surface colors for ALL light themes.
// M3 tints surfaces with the primary palette (e.g. violet → purple inputs/selects).
// The AngularJS Common sub-theme uses accentPalette('grey') for input backgrounds,
// so all Angular Material surfaces must be neutral grey/white, not tinted.
// Must come AFTER all per-theme mat.all-component-colors() blocks to win the cascade.
// ============================================================================
body.p3xr-theme-light {
  // Surfaces: pure white (no primary tint)
  --mat-select-panel-background-color: #ffffff;
  --mat-dialog-container-color: #ffffff;
  --mat-menu-container-color: #ffffff;
  --mat-autocomplete-background-color: #ffffff;
  --mat-datepicker-calendar-container-background-color: #ffffff;
  --mat-card-outlined-container-color: #ffffff;
  --mat-table-background-color: #ffffff;
  --mat-paginator-container-background-color: #ffffff;
  // Form fields: neutral grey (matching AngularJS Common accent=grey)
  --mdc-filled-text-field-container-color: #f5f5f5;
  --mat-form-field-filled-container-color: #f5f5f5;
  // Options / selections
  --mat-option-selected-state-layer-color: rgba(0, 0, 0, 0.12);
  --mat-option-label-text-color: rgba(0, 0, 0, 0.87);
}

// Redis overrides p3xr-theme-light background — must come after body.p3xr-theme-light to win cascade
body.p3xr-mat-theme-redis {
  --mat-app-background-color: #ffebee;  // red-50 (lightest red)
}

// Same neutralization for dark themes — M3 tints dark surfaces with primary palette too.
// All dark themes use Common accentPalette('grey') except Matrix (light-green),
// but ALL should use neutral grey for input backgrounds.
body.p3xr-theme-dark {
  // Surfaces: neutral dark grey (no primary tint)
 
  --mat-select-panel-background-color: #424242;
  --mat-dialog-container-color: #424242;
  --mat-menu-container-color: #424242;
  --mat-autocomplete-background-color: #424242;
  --mat-datepicker-calendar-container-background-color: #424242;
  --mat-card-outlined-container-color: #424242;
  --mat-table-background-color: #303030;
  --mat-paginator-container-background-color: #303030;
  // Form fields: neutral dark grey (matching AngularJS Common accent=grey)
  --mdc-filled-text-field-container-color: #404040;
  --mat-form-field-filled-container-color: #404040;
  // Options / selections
  --mat-option-selected-state-layer-color: rgba(255, 255, 255, 0.12);
  --mat-option-label-text-color: rgba(255, 255, 255, 0.87);
}

// ============================================================================
// Force AngularJS input/dialog backgrounds to neutral (matching Common accentPalette='grey').
// AngularJS Material's runtime $mdTheming CSS tints surfaces with the primary palette.
// These overrides use high specificity to beat the runtime-generated theme CSS.
// ============================================================================
body md-dialog,
body md-dialog md-dialog-content,
body md-dialog md-dialog-content md-content,
body [md-theme] md-dialog,
body [md-theme] md-dialog md-dialog-content {
  background-color: var(--p3xr-dialog-surface-bg) !important;
}

// All form controls: inputs, textareas, selects, switches, checkboxes
body md-input-container,
body md-input-container .md-input,
body md-input-container input,
body md-input-container textarea,
body md-select,
body md-select md-select-value,
body md-switch,
body md-checkbox,
body md-radio-button,
body [md-theme] md-input-container,
body [md-theme] md-input-container .md-input,
body [md-theme] md-input-container input,
body [md-theme] md-input-container textarea,
body [md-theme] md-select,
body [md-theme] md-select md-select-value,
body [md-theme] md-switch,
body [md-theme] md-checkbox,
body [md-theme] md-radio-button {
  background-color: transparent !important;
}

// Select dropdown panel and menu content
body md-select-menu,
body md-select-menu md-content,
body md-option,
body [md-theme] md-select-menu,
body [md-theme] md-select-menu md-content {
  background-color: var(--p3xr-dialog-surface-bg) !important;
}

// Fieldset backgrounds inside dialogs (SSH section etc.)
body md-dialog fieldset,
body [md-theme] md-dialog fieldset {
  background-color: transparent !important;
}


// Tree node tooltip: shift 36px right (node label + action buttons)
.p3xr-tree-node-tooltip {
  margin-left: 36px !important;
}