/* Styles for the shell chrome.
 *
 * These rules previously lived in each host's own stylesheet (nexus-platform's app.css,
 * management.css and ManagementLayout.razor.css), which is why a second product could not adopt
 * the shell without its logo, account button and chips rendering unstyled. They travel with the
 * shell now.
 *
 * Everything is expressed against Bootstrap's --bs-* custom properties, so light and dark mode
 * follow the `data-bs-theme` attribute with no extra rules. */

/* ---------------------------------------------------------------- brand / logo box */

.nexeriq-logo-link,
.main-nav .logo-box .nexeriq-logo-link,
.main-nav .logo-box .nexeriq-logo-link:hover {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
    min-width: 0;
    text-decoration: none;
}

.nexeriq-logo-sm {
    width: 2rem;
    height: 2rem;
}

.nexeriq-logo-lg {
    max-width: 8.75rem;
    max-height: 2.25rem;
}

/* Theme axis only. Which of the two marks inside a brand shows — the small one or the lockup — is the
   SIZE axis, and Velex owns that (`.logo-box .logo-sm` / `.logo-lg`, driven by data-menu-size).
   These rules therefore never set `display` on an image: they show or hide the whole brand, and
   `display: contents` lets Velex's descendant rules keep reaching the images inside the visible one.

   Setting `display` on the images here instead is what caused a condensed rail to render the light and
   dark mark side by side, and a dark expanded rail to render the small mark and the lockup together —
   each axis overrode the other's `display` depending on which stylesheet won the cascade. */
.app-brand {
    display: contents;
}

.app-brand-dark {
    display: none;
}

[data-bs-theme="dark"] .app-brand-light {
    display: none;
}

[data-bs-theme="dark"] .app-brand-dark {
    display: contents;
}

/* ---------------------------------------------------------------- topbar */

.topbar .navbar-header {
    gap: 1rem;
}

.topbar-page-icon {
    width: 1.5rem;
    height: 1.5rem;
    flex: 0 0 auto;
    object-fit: contain;
}

.tenant-chip {
    align-items: center;
    gap: 0.65rem;
    max-width: 24rem;
    min-height: 2.5rem;
    padding: 0.35rem 0.75rem;
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background: var(--bs-secondary-bg);
    color: var(--bs-body-color);
}

.workspace-chip {
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0;
    line-height: 1.15;
}

.workspace-chip strong {
    max-width: 14rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--bs-heading-color);
}

.app-account-button {
    padding: 0;
    overflow: hidden;
}

.app-account-button .avatar-sm,
.app-account-button .avatar-title {
    width: 2.25rem;
    height: 2.25rem;
}

.app-account-button .avatar-title {
    font-size: 0.82rem;
}

/* ---------------------------------------------------------------- shell height */

/* The shell must fill the viewport whatever wraps it. DxDrawer inserts two elements between <body>
 * and Velex's .wrapper, and neither is told to stretch, so the chain can collapse to its content
 * and strand the footer in the middle of a tall window. Velex sizes .page-content with `100vh`,
 * which the mobile browser chrome lies about; `100dvh` is the honest one. */
html,
body {
    min-height: 100%;
}

.app-right-drawer,
.app-right-drawer > .dxbl-drawer-content,
.app-right-drawer .wrapper {
    min-height: 100dvh;
}

.app-right-drawer .wrapper .page-content {
    min-height: 100dvh;
}

/* ---------------------------------------------------------------- right drawer */

/* DevExpress's DxDrawer reserves its default 300px panel width as a margin on the content, even
 * when the panel is closed and the mode is Overlap. Left alone, every page in the shell silently
 * loses 300px of width to a drawer nobody opened. */
.app-right-drawer .wrapper {
    margin-right: 0;
}

/* ---------------------------------------------------------------- page content */

.app-page-content {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    padding: 1.25rem 0 2rem;
}

.app-page {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* ---------------------------------------------------------------- search */

.app-search {
    position: relative;
    min-width: 16rem;
}

.app-search-input {
    position: relative;
    display: flex;
    align-items: center;
}

.app-search-input .form-control {
    padding-left: 2.25rem;
}

.app-search-icon {
    position: absolute;
    left: 0.75rem;
    pointer-events: none;
    color: var(--bs-secondary-color);
}

.app-search-results {
    position: absolute;
    top: calc(100% + 0.35rem);
    right: 0;
    left: 0;
    z-index: 1050;
    max-height: 24rem;
    overflow-y: auto;
    padding: 0.35rem;
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background: var(--bs-body-bg);
    box-shadow: var(--bs-box-shadow);
}

.app-search-group + .app-search-group {
    margin-top: 0.35rem;
    border-top: var(--bs-border-width) solid var(--bs-border-color);
    padding-top: 0.35rem;
}

.app-search-group-title {
    padding: 0.25rem 0.5rem;
    color: var(--bs-secondary-color);
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
}

.app-search-result {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.45rem 0.5rem;
    border: 0;
    border-radius: var(--bs-border-radius-sm);
    background: transparent;
    color: var(--bs-body-color);
    text-align: left;
}

.app-search-result:hover,
.app-search-result.is-active {
    background: var(--bs-secondary-bg);
}

/* Keyboard users must be able to see which result Enter will activate. */
.app-search-result:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: -2px;
}

.app-search-result-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.app-search-result-title,
.app-search-result-subtitle {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-search-result-subtitle {
    color: var(--bs-secondary-color);
    font-size: 0.8rem;
}

/* ---------------------------------------------------------------- error bar */

#blazor-error-ui {
    display: none;
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 1080;
    max-width: 36rem;
    padding: 0.75rem 2.25rem 0.75rem 1rem;
    border: 1px solid var(--bs-danger-border-subtle);
    border-radius: var(--bs-border-radius);
    color: var(--bs-danger-text-emphasis);
    background: var(--bs-danger-bg-subtle);
    box-shadow: var(--bs-box-shadow-lg);
}

#blazor-error-ui .dismiss {
    position: absolute;
    top: 0.6rem;
    right: 0.75rem;
    cursor: pointer;
}

/* Blazor's <FocusOnNavigate> moves focus to the page heading after each navigation so a screen
 * reader announces the new page. A heading is not a control, so a focus ring around it reads as a
 * rendering bug — but a real keyboard user must still see where focus is, hence :not(:focus-visible). */
[tabindex="-1"]:focus:not(:focus-visible) {
    outline: none;
}

/* ---------------------------------------------------------------- nav item badge */

/* A trailing count pill on a nav item (an unread mail count, say). Sits at the far end of the
 * row, pushed there by auto margin so it right-aligns regardless of label length. Kept muted so
 * it reads as metadata, not a call to action; the active item's own colour still wins. */
.main-nav .navbar-nav .nav-link .nav-badge {
    margin-left: auto;
    min-width: 1.25rem;
    padding: 0 0.4rem;
    border-radius: 0.75rem;
    background-color: var(--bs-secondary-bg, rgba(152, 165, 177, 0.18));
    color: var(--bs-secondary-color, #9aa5b1);
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1.25rem;
    text-align: center;
    white-space: nowrap;
}

/* When the sidebar is condensed to an icon rail the label is hidden; a numeric badge would
 * overflow the narrow rail, so collapse it to a small dot indicating "unread present". */
[data-menu-size="condensed"] .main-nav .navbar-nav .nav-link {
    position: relative;
}

[data-menu-size="condensed"] .main-nav .navbar-nav .nav-link .nav-badge {
    position: absolute;
    top: 0.5rem;
    right: 0.75rem;
    min-width: 0.5rem;
    width: 0.5rem;
    height: 0.5rem;
    padding: 0;
    border-radius: 50%;
    font-size: 0;
    line-height: 0;
    overflow: hidden;
}

/* ---------------------------------------------------------------- dark-mode contrast */

/* Velex's muted text is #8391a2, which is 4.21:1 on the dark card surface (#282f36) — below WCAG
 * AA's 4.5:1 for body text, and it is the colour of every hint, help text and timestamp in the UI.
 * Measured with axe-core; #9aa5b1 lands at 5.5:1. Light mode already passes, so this is scoped.
 *
 * Three further findings are the brand orange itself (active nav text, avatar initials, and the
 * outline-secondary button) and are left alone: changing them is a design decision that would
 * repaint every NexerIQ product, not a bug fix. See Documentation/Architecture/09 in
 * devop-mail-server. */
[data-bs-theme="dark"] {
    --bs-secondary-color: #9aa5b1;
}
