/* ---------------------------------------------------------------- focus rings

   On navigation the shell moves focus to the page's <h1> (tabindex="-1") so a screen reader announces
   where it just landed. The browser then draws its default focus ring around the heading, and every page
   in the app appears to have a black box round its title.

   Suppressing it only for :not(:focus-visible) is not enough: on a hard load or a refresh there is no prior
   user interaction to judge by, so the browser treats the scripted focus as keyboard-driven and draws the
   ring anyway — which is precisely when people saw the box.

   tabindex="-1" means the element is NOT in the tab order, so no keyboard user ever lands on it by tabbing.
   A focus ring there communicates nothing to anyone; the announcement is the point, not the outline. This
   only ever applies to elements a script has focused deliberately, never to a real control. */
[tabindex="-1"]:focus {
    outline: none;
}

.app-right-drawer {
    --app-right-drawer-width: min(100vw, 700px);
    /* The drawer supplies its own header and body chrome, so DevExpress must not pad the panel. */
    --dxbl-drawer-panel-body-padding-x: 0;
    --dxbl-drawer-panel-body-padding-y: 0;
    min-height: 100dvh;
}

.app-right-drawer .dxbl-drawer-panel {
    width: var(--app-right-drawer-width);
    max-width: 100vw;
}

.app-right-drawer-open .dxbl-drawer-panel {
    box-shadow: -0.75rem 0 2rem rgba(15, 23, 42, 0.18);
}

.app-right-drawer .dxbl-drawer-panel > .dxbl-drawer-header {
    width: 100%;
    padding: 0;
}

.app-right-drawer .dxbl-drawer-panel > .dxbl-drawer-body {
    width: 100%;
    padding: 0;
}

.app-right-drawer-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    padding: 1rem 1.25rem;
    border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

.app-right-drawer-title {
    min-width: 0;
}

.app-right-drawer-title h3 {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    font-size: 1rem;
    line-height: 1.35;
}

.app-right-drawer-title h3 span,
.app-right-drawer-subtitle {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-right-drawer-subtitle {
    display: block;
    margin-top: 0.25rem;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

.app-right-drawer-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 0 0 auto;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.app-right-drawer-body {
    width: 100%;
    padding: 1rem;
    overflow-x: hidden;
}

.app-right-drawer-body.app-right-drawer-body-flush {
    padding: 0;
}

.entity-note-markdown-editor .dxbl-tabs-content-panel {
    padding: 0;
}

.entity-note-markdown-editor .note-preview {
    min-height: 10rem;
    padding: 0.75rem;
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background: var(--bs-body-bg);
}

.app-icon-avatar-title-image,
.app-icon-avatar-image {
    object-fit: cover;
}

.app-entity-option {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
}

.app-entity-option__text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.app-entity-option__title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-entity-option__description {
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

.app-dropdown-icon-only,
.app-dropdown-icon-only .dxbl-btn-dropdown-toggle {
    width: 2rem;
    min-width: 2rem;
}

.app-dropdown-icon-only .dxbl-btn-caption {
    display: none;
}

/* A destructive item in an AppDropdown, e.g. Delete. Tinted so it reads as the dangerous one
   without being loud until hovered. */
.app-dropdown-item-danger {
    color: var(--bs-danger);
}

.app-dropdown-item-danger:hover {
    background-color: var(--bs-danger);
    color: #fff;
}

.app-state-info {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 8rem;
    padding: 1.5rem;
    color: var(--bs-secondary-color);
    text-align: center;
}

.app-toolbar,
.app-toolbar-start,
.app-toolbar-content,
.app-toolbar-end {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.app-toolbar {
    justify-content: space-between;
}

.app-toolbar-content {
    min-width: 0;
    flex: 1 1 auto;
}

.app-grid-toolbar {
    padding: 0.75rem;
    border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

.app-grid-search {
    min-width: min(24rem, 100%);
}

.app-grid-ai-filter-chip {
    display: inline-flex;
    align-items: center;
    max-width: 22rem;
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    font-size: 0.8125rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--bs-primary-text-emphasis, var(--bs-primary));
    background-color: var(--bs-primary-bg-subtle, rgba(13, 110, 253, 0.1));
}

/* Ribbon command surface (AppGrid RibbonEnable). The DxRibbon panel renders at
   content width and the grid's toolbar container is padded (--dxbl-grid-toolbar-
   container-padding-x: 1rem), so the ribbon stops short and its items sit inset
   from the columns (cell padding is only .375rem). Stretch it to full width
   (higher specificity beats DX theme rules) and zero the toolbar container's
   horizontal padding so the ribbon is flush and its items align with the columns. */
.app-grid:has(.app-grid-ribbon) {
    --dxbl-grid-toolbar-container-padding-x: 0;
}

.app-grid .app-grid-ribbon {
    width: 100%;
    background-color: transparent;
    border: 0;
    /* Drop the ribbon's own bottom divider; the grid header already separates the
       command surface from the data, so one line reads calmer than stacked borders. */
    --dxbl-ribbon-border-bottom-width: 0;
}

/* Roomier grid rows + semibold header text for clearer column hierarchy. Vertical
   column lines are removed natively via the DxGrid GridlinesVisible="Gridlines.Horizontal"
   parameter (see AppGrid), not CSS. */
.app-grid {
    --dxbl-grid-text-cell-padding-y: 0.5rem;
    --dxbl-grid-header-font-weight: 600;
}

/* Search hosted inside a ribbon item template (Home tab) */
.app-grid-ribbon-search-item {
    padding: 0;
}

.app-grid-ribbon-search-item:hover {
    background-color: transparent;
}

.app-grid-ribbon-search {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.app-grid-ribbon-search-box {
    min-width: min(16rem, 60vw);
}

/* Column picker (AppColumnPicker) */
.app-grid-ribbon-columns-item {
    padding: 0;
}

.app-column-picker-body {
    width: 100%;
    overflow-x: hidden;
}

.app-column-picker-search {
    margin-bottom: 0.5rem;
}

.app-column-picker-list {
    max-height: 24rem;
    overflow-x: hidden;
    overflow-y: auto;
}

.app-column-picker-row {
    padding: 0.2rem 0.15rem;
}

.app-column-picker-row:hover {
    background: var(--bs-tertiary-bg);
    border-radius: 0.25rem;
}

.app-column-picker-all {
    border-bottom: var(--bs-border-width) solid var(--bs-border-color);
    margin-bottom: 0.35rem;
    padding-bottom: 0.5rem;
}

.app-quick-link {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    height: 100%;
}

.app-quick-link-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
}

@media (max-width: 575.98px) {
    .app-right-drawer-header {
        padding: 0.875rem 1rem;
    }

    .app-right-drawer-body {
        padding: 0.875rem;
    }

    .app-toolbar,
    .app-toolbar-start,
    .app-toolbar-content,
    .app-toolbar-end {
        flex-wrap: wrap;
    }
}

/* Below the tablet breakpoint the DxGrid compresses every column to fit the
   viewport, which clips all headers to "…". Give the table a minimum width so
   columns keep a readable size and the grid scrolls horizontally instead
   (NEXER-190). Grids that opt into @bind-IsXSmall additionally drop secondary
   columns on phones, so the remaining columns fit without much scrolling. */
@media (max-width: 767.98px) {
    .app-grid:not(.app-grid-adaptive) .dxbl-grid-table {
        min-width: 44rem;
    }
}

/* Floating column-chooser button shown on phone viewports (AppGrid
   MobileColumnChooserFab) so users can reveal columns hidden by the adaptive
   layout. Anchored to the viewport bottom-right, above content. */
.app-grid-fab {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 1030;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    border: none;
    border-radius: 50%;
    color: #fff;
    background-color: var(--bs-primary);
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.3);
    font-size: 1.1rem;
}

.app-grid-fab:hover,
.app-grid-fab:focus-visible {
    filter: brightness(1.08);
    outline: none;
}

/* ============================================================
   APP FILE VIEWER
   ============================================================ */

.app-file-viewer {
    width: 100%;
    height: 100%;
}

.app-file-viewer-pdf {
    display: flex;
    flex-direction: column;
    height: 600px;
    min-height: 600px;
}

.app-file-viewer-pdf-inner {
    flex: 1;
}

.app-file-viewer-image {
    align-items: center;
    display: flex;
    justify-content: center;
    padding: 1rem;
}

.app-file-viewer-img {
    border-radius: .375rem;
    box-shadow: 0 2px 8px rgba(0,0,0,.12);
    max-height: 80vh;
    max-width: 100%;
    object-fit: contain;
}

.app-file-viewer-fallback {
    align-items: center;
    color: var(--bs-secondary-color);
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 200px;
    padding: 2rem;
    text-align: center;
}

/* ============================================================
   APP RIGHT DRAWER ACCOUNT MENU
   ============================================================ */
.app-right-menu-content {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    min-height: 0;
    color: var(--bs-body-color);
}

.app-right-menu-scroll {
    flex: 1 1 auto;
    min-height: 0;
    padding: 1.15rem;
    overflow-y: auto;
}

.app-right-menu-profile {
    display: flex;
    align-items: center;
    gap: 0.95rem;
    min-width: 0;
    padding-bottom: 1.1rem;
}

.app-right-menu-profile-avatar {
    flex: 0 0 auto;
}

.app-right-menu-profile-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.app-right-menu-user-name,
.app-right-menu-user-email {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-right-menu-user-name {
    font-size: 1rem;
    font-weight: 600;
}

.app-right-menu-user-email {
    color: var(--bs-secondary-color);
    font-size: 0.85rem;
}

.app-right-menu-tenant {
    display: grid;
    gap: 0.55rem;
    margin: 0;
    padding: 0.95rem 0;
    border-top: var(--bs-border-width) solid var(--bs-border-color);
    border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

.app-right-menu-tenant div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    min-width: 0;
}

.app-right-menu-tenant dt {
    flex: 0 0 auto;
    color: var(--bs-secondary-color);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
}

.app-right-menu-tenant dd {
    min-width: 0;
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
}

.app-right-menu-section {
    display: grid;
    gap: 0.75rem;
    padding: 1.05rem 0;
    border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

.app-right-menu-section-title {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    color: var(--bs-secondary-color);
    font-size: 0.85rem;
    font-weight: 600;
}

.app-right-menu-section-title i {
    width: 1.25rem;
    color: var(--bs-primary);
    text-align: center;
}

.app-right-menu-theme-options {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
}

.app-right-menu-theme-option {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    min-width: 0;
    min-height: 2.5rem;
    padding: 0.5rem 0.75rem;
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    color: var(--bs-body-color);
    background: var(--bs-secondary-bg);
    font-weight: 600;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.app-right-menu-theme-option:hover:not(:disabled) {
    border-color: rgba(var(--bs-primary-rgb), 0.45);
    color: var(--bs-primary);
}

.app-right-menu-theme-option.is-active {
    border-color: rgba(var(--bs-primary-rgb), 0.55);
    color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.1);
}

.app-right-menu-theme-option:disabled {
    cursor: default;
    opacity: 0.7;
}

.app-right-menu-culture .culture-selector {
    color: var(--bs-body-color);
}

.app-right-menu-culture .culture-selector > span {
    display: none;
}

.app-right-menu-culture .culture-selector select {
    min-height: 2.5rem;
}

.app-right-menu-footer {
    flex: 0 0 auto;
    padding: 0.85rem 1.15rem;
    border-top: var(--bs-border-width) solid var(--bs-border-color);
    background: var(--bs-body-bg);
}

.app-right-menu-signout {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.55rem;
    width: 100%;
    min-height: 2.5rem;
    border: var(--bs-border-width) solid var(--bs-danger-border-subtle);
    border-radius: var(--bs-border-radius);
    color: var(--bs-danger);
    font-weight: 600;
}

.app-right-menu-signout:hover {
    color: var(--bs-danger-text-emphasis);
    background: var(--bs-danger-bg-subtle);
    text-decoration: none;
}

/* ---------------------------------------------------------------- form fields */

.app-field + .app-field {
    margin-top: 0.75rem;
}

.app-field-required {
    margin-left: 0.15rem;
    color: var(--bs-danger);
}

/* ---------------------------------------------------------------- tag box */

/* AppTagBox wraps DxTagBox, so its chips, drop-down and remove buttons are DevExpress's own DOM — we do NOT
   restyle them. This class only lets the editor fill the field width. The earlier rules here set
   `display:flex; flex-direction:column` on the editor root and hand-rolled `.app-tagbox-tag*` chips; both were
   left over from the pre-DxTagBox control, and the column layout was actively wrong — it forced DevExpress's
   inline chip row to stack full-width, one pill per line. */
.app-tagbox {
    width: 100%;
}

/* Only used when the app supplies a TagTemplate: lay its content out beside the remove button we add. Default
   (untemplated) chips are DevExpress's own and are not touched. */
.app-tagbox-tag {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.app-tagbox-tag-remove {
    padding: 0;
    opacity: 0.6;
}

.app-tagbox-tag-remove:hover {
    opacity: 1;
}

/* ---------------------------------------------------------------- breadcrumbs */

/* The theme sets the divider to an icon-font codepoint ("\ea50"). An app that ships the theme's CSS but not
   that font gets a tofu box between every crumb — which is what the mail portal showed. A text separator
   needs no font to be present. */
.app-breadcrumb {
    --bs-breadcrumb-divider: "\203A"; /* › */
}

/* ---------------------------------------------------------------- code block */

.app-code-block-label {
    margin-bottom: 0.2rem;
    color: var(--bs-secondary-color);
    font-size: 0.8rem;
}

.app-code-block-frame {
    position: relative;
}

.app-code-block-body {
    margin: 0;
    padding: 0.6rem 0.75rem;
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-sm);
    background: var(--bs-tertiary-bg);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: 0.85rem;
}

/* The block is focusable so a keyboard user can scroll and select it. */
.app-code-block-body:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 1px;
}

/* The copy button floats over the top-right corner; the body reserves room for it so a long
   single-line value (a token, an invitation link) never runs underneath it. */
.app-code-block-frame:has(.app-code-block-copy) .app-code-block-body {
    padding-right: 3rem;
}

.app-code-block-copy {
    position: absolute;
    top: 0.3rem;
    right: 0.3rem;
}

/* ---------------------------------------------------------------- radio group */

.app-radio-group {
    min-width: 0;
    padding: 0;
    border: 0;
}

.app-radio-group-legend {
    float: none; /* Bootstrap floats legends; that breaks the fieldset's own layout. */
    width: auto;
    margin-bottom: 0.4rem;
    padding: 0;
    font-size: 1rem;
    font-weight: 500;
}

.app-radio-option + .app-radio-option {
    margin-top: 0.4rem;
}

.app-radio-option .form-check-label {
    display: flex;
    flex-direction: column;
}

.app-radio-option-description {
    color: var(--bs-secondary-color);
    font-size: 0.85rem;
}

/* ---------------------------------------------------------------- AppNavTabs

   One row that scrolls, rather than a block that wraps. An area with a dozen sections wrapped into a second
   row of tabs, which reads as two separate strips and pushes the page content down; scrolling keeps the
   strip a strip. The scrollbar is hidden because the tabs themselves are the affordance, and the row still
   responds to a trackpad, a shift-wheel and a keyboard. */
.nav-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
}

.nav-tabs::-webkit-scrollbar {
    display: none;
}

.nav-tabs .nav-link {
    white-space: nowrap;
}

/* ---------------------------------------------------------------- text box with buttons */

/* An AppTextBox with Buttons renders as a Bootstrap input-group. The field keeps its rounded leading edge,
   the buttons keep the trailing one, and the group fills the field's column rather than the whole row. */
.app-textbox-group {
    flex-wrap: nowrap;
}

.app-textbox-group > .form-control {
    min-width: 0;
}

/* An invalid field still owns the group's border colour, so the error state does not stop at the button. */
.app-textbox-group > .form-control.is-invalid ~ .btn {
    border-color: var(--bs-form-invalid-border-color);
}

/* ---------------------------------------------------------------- drawer form */

/* An App* editor inside a DxFormLayout is not a DxFormLayoutItem: the layout gives it its content width and
   flows the next one alongside, so three fields end up in a ragged row with their labels at different
   heights. In a drawer a field is full width, one per row. DxFormLayoutItem children keep their own spans —
   this only claims the fields the layout has no opinion about. */
.app-drawer-form > .app-field,
.app-drawer-form > .app-code-block,
.app-drawer-form > .app-drawer-form-actions {
    flex: 0 0 100%;
    max-width: 100%;
    width: 100%;
}

.app-drawer-form > .app-field {
    margin-bottom: 0.75rem;
}

/* ---------------------------------------------------------------- tabs (left rail) */

/* A left rail reads better than a horizontal strip when each tab holds a table of its own: the tables all
   start at the same place, and the eye does not have to travel back up to see which one it is looking at. */
.app-tabs-left {
    display: flex;
    align-items: flex-start;
    gap: 1.25rem;
}

.app-tabs-left > .nav-tabs {
    flex: 0 0 auto;
    min-width: 11rem;
    border-bottom: 0;
    border-right: var(--bs-border-width) solid var(--bs-border-color);
}

.app-tabs-left > .nav-tabs .nav-link {
    width: 100%;
    text-align: left;
    border: 0;
    border-radius: var(--bs-border-radius);
    margin-bottom: 0.15rem;
}

.app-tabs-left > .nav-tabs .nav-link.active {
    background: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis, var(--bs-primary));
}

.app-tabs-left > .tab-content {
    flex: 1 1 auto;
    min-width: 0;
    padding-top: 0;
}

/* The rail stacks above the content when there is no room beside it. */
@media (max-width: 767.98px) {
    .app-tabs-left {
        flex-direction: column;
    }

    .app-tabs-left > .nav-tabs {
        width: 100%;
        border-right: 0;
        border-bottom: var(--bs-border-width) solid var(--bs-border-color);
    }
}

/* A hint that belongs to the field above it — a live address preview, say — and not to the form layout's
   idea of a column. */
.app-drawer-form > .form-text {
    flex: 0 0 100%;
    max-width: 100%;
    margin-top: -0.5rem;
    margin-bottom: 0.75rem;
}

/* ---------------------------------------------------------------- state blocks */

/* Loading, empty, error and information all look the same: a centred line of text with, at most, one thing
   to do about it. Only the information kind was ever styled, so an empty grid's "New" button inherited the
   grid's empty-data area instead — stretched to a slab, its icon wrapped onto its own line. */
.app-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 2rem 1.5rem;
    color: var(--bs-secondary-color);
    text-align: center;
}

.app-state-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.75rem;
}

/* A button in a state block is a button, not a panel: it takes the width of its own label. */
.app-state-actions .btn,
.app-state-actions .dxbl-btn {
    width: auto;
    flex: 0 0 auto;
}

/* The grid's empty area blows every icon inside it up to 3rem — meant for a big "nothing here" glyph, but it
   catches the icon on our New button too, which is why the button came out a 62px slab with its icon stacked
   above the label. The button's icon is the size of its text, wherever the button happens to be. */
.dxbl-grid .dxbl-grid-empty-data-area .app-state-actions .dxbl-image {
    width: 1em;
    height: 1em;
}
