.app-modal {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal, 1300);
    display: grid;
    place-items: center;
    padding: 1rem;
}

.app-modal[hidden] {
    display: none !important;
}

.app-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.42);
}

/* Height is bounded by the SCREEN, not by an arbitrary figure.
 *
 * This was `min(42rem, calc(100vh - 2rem))`, and 42rem is not 672px here: the app sets its root
 * font to 14px, so the cap resolved to 588px. On a 950px window that left 330px of usable
 * screen empty while the dialog scrolled -- measured on the payment-plan detail modal with
 * twelve instalments, 929px of content squeezed into 588.
 *
 * A modal taller than the window still has to scroll somewhere; what changes is that it now
 * uses the whole window first. Pages that want the full-height shape with a scrolling body and
 * pinned header/footer keep opting in through .app-modal__dialog--viewport.
 */
.app-modal-dialog {
    position: relative;
    z-index: 1;
    width: min(42rem, 100%);
    max-height: calc(100vh - 2rem);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, #d0d7de);
    border-radius: var(--radius-lg, 0.75rem);
    box-shadow: var(--shadow-xl, 0 18px 50px rgba(15, 23, 42, 0.22));
}

.app-modal-header,
.app-modal-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem;
    border-color: var(--color-border, #d0d7de);
}

.app-modal-header {
    border-bottom: 1px solid var(--color-border, #d0d7de);
}

.app-modal-header h2 {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
}

.app-modal-body {
    padding: 1rem;
    display: grid;
    gap: 1rem;
}

.app-modal-footer {
    justify-content: flex-end;
    border-top: 1px solid var(--color-border, #d0d7de);
}

/* The title and the buttons stay put; only the content moves.
 *
 * The dialog used to be the scroller, so a tall modal scrolled as one piece: measured on the
 * payment-plan detail modal with 30 instalments, the Save/Cancel footer was below the fold when
 * it opened, and scrolling down to reach it took the title off the top. Both ends now hold
 * their place and the middle scrolls -- which is what .app-modal__dialog--viewport already did
 * for the three modals that opted into it.
 *
 * `min-height: 0` is the load-bearing half: a flex item will not shrink below its content
 * without it, so the body would have pushed the footer off the bottom again.
 *
 * The `> form` is not decoration. Two modals -- settings/users and settings/roles -- hang a
 * <form class="app-module-form"> directly off the dialog instead of an .app-modal-body. Without
 * naming it, `overflow: hidden` above would clip those two with nothing able to scroll. Checked
 * across 26 modals on 10 pages: those are the only two, and every other dialog holds a header,
 * a body and a footer and nothing else.
 */
.app-modal-dialog > .app-modal-header,
.app-modal-dialog > .app-modal-footer,
.app-modal__dialog > .app-modal__header,
.app-modal__dialog > .app-modal__footer,
.app-modal__panel > .app-modal__header,
.app-modal__panel > .app-modal__footer {
    flex: 0 0 auto;
}

/* .app-modal__panel is a third spelling of the same box -- collections/reports/schedules uses
   it -- and it is bounded and clipping like the other two. Left out, its <form> kept
   `overflow: hidden` from .app-module-form and the content below the fold could not be
   reached: measured with 40 rows of filler, panel 922px and clipping, form overflowing with
   nothing able to scroll. */
.app-modal-dialog > .app-modal-body,
.app-modal-dialog > form,
.app-modal__dialog > .app-modal__body,
.app-modal__dialog > form,
.app-modal__panel > .app-modal__body,
.app-modal__panel > form {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
}

body.app-modal-open {
    overflow: hidden;
}

/* app_modal() component — BEM classes (public/shared/components/modal.php) */
.app-modal {
    grid-template-areas: 'stack';
}

.app-modal__backdrop,
.app-modal__dialog {
    grid-area: stack;
}

.app-modal__backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.52);
    z-index: 0;
}

.app-modal__dialog {
    position: relative;
    z-index: 1;
    align-self: center;
    justify-self: center;
    width: min(42rem, calc(100vw - 2rem));
    /* See the note above .app-modal-dialog: the 42rem height cap resolved to 588px. */
    max-height: calc(100vh - 2rem);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, #d0d7de);
    border-radius: var(--radius-lg, 0.75rem);
    box-shadow: var(--shadow-xl, 0 18px 50px rgba(15, 23, 42, 0.22));
}

.app-modal__header,
.app-modal__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem;
    border-color: var(--color-border, #d0d7de);
    background: var(--color-surface, #fff);
}

.app-modal__header {
    border-bottom: 1px solid var(--color-border, #d0d7de);
}

.app-modal__title {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
}

.app-modal__body {
    padding: 1rem;
    background: var(--color-surface, #fff);
}

.app-modal__footer {
    justify-content: flex-end;
    border-top: 1px solid var(--color-border, #d0d7de);
}

.app-modal__close {
    border: 0;
    background: transparent;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
    color: var(--color-text-muted, #667085);
}

.app-modal__dialog--wide {
    width: min(80rem, calc(100vw - 1.5rem));
}

.app-modal__dialog--xl {
    width: min(90rem, calc(100vw - 1.5rem));
}

/* Every dialog is now a flex column that keeps its header and footer and scrolls its body, so
   this modifier no longer has to arrange any of that -- repeating it here is how the two would
   drift apart. What it still carries is the tighter chrome the three pages using it want for a
   full-height table. */
.app-modal__dialog--viewport {
    max-height: calc(100vh - 1.5rem);
}

.app-modal__dialog--viewport .app-modal__header,
.app-modal__dialog--viewport .app-modal__footer {
    flex-shrink: 0;
    padding: 0.625rem 1rem;
}

.app-modal__dialog--viewport .app-modal__body {
    flex: 1;
    overflow: auto;
    padding: 0.75rem 1rem;
}

.app-modal__body--table {
    min-width: 0;
}

.app-modal__body--table .app-table-wrap {
    overflow-x: auto;
}
