/*
Dialog

<dialog class="dialog-overlay">     top layer, fills the viewport, backdrop
  <div class="dialog is-md">       the panel: role comes from <dialog>
    .dialog-header > .dialog-title + .dialog-description
    ...content...
    .dialog-footer
    .dialog-close                   the corner X

Enter and exit animate off data-state="open|closed" on both the overlay
and the panel. Durations, easing, scale and colors are theme tokens; a
theme with zero durations gets no animation and no delay.
*/

@layer components {

.dialog-root,
.dialog-trigger,
.dialog-close-part {
  display: contents;
}

.dialog-overlay {
  --dialog-inset: var(--space-4);

  /* Undo the user agent's modal dialog box. */
  position:   fixed;
  inset:      0;
  width:      100%;
  height:     100%;
  max-width:  none;
  max-height: none;
  margin:     0;
  padding:    var(--dialog-inset);
  border:     0;
  color:      var(--ink);
  background: var(--backdrop);
  backdrop-filter: blur(var(--backdrop-blur));
  overflow-y: auto;
  overscroll-behavior: contain;
  z-index:    var(--z-modal);
}

.dialog-overlay[open] {
  display:     grid;
  place-items: center;
}

.dialog-overlay::backdrop {
  background: transparent;
}

.dialog-overlay:not([data-modal="true"]) {
  background:      none;
  backdrop-filter: none;
  pointer-events:  none;
}

.dialog-overlay:not([data-modal="true"]) > .dialog {
  pointer-events: auto;
}

/* A modal dialog opened inside another modal draws no backdrop of its own
   (Base UI): the outer one already dims the page, so the page does not
   darken a step with each level. The overlay still takes the outside press.
   An alert dialog keeps its backdrop over the panel it interrupts (Base UI
   AlertDialog's backdrop is forceRender). */
.dialog-overlay[data-modal="true"] .dialog-overlay[data-modal="true"]:not(.alert-dialog-overlay) {
  background:      none;
  backdrop-filter: none;
}

.dialog {
  position:       relative;
  display:        flex;
  flex-direction: column;
  gap:            var(--dialog-gap);
  width:          100%;
  max-width:      var(--dialog-width);
  padding:        var(--dialog-padding);
  background:     var(--dialog-bg);
  color:          var(--ink);
  border:         var(--dialog-border-width) solid var(--dialog-border);
  border-radius:  var(--radius-dialog);
  box-shadow:     var(--dialog-shadow);
  outline:        none;
  /* A grid item's min-width is auto: without this, one long unbroken word
     widens the panel past a phone viewport. */
  min-width:      0;
  overflow-wrap:  anywhere;
}

.dialog.is-sm   { max-width: var(--container-sm); }
.dialog.is-lg   { max-width: var(--container-3xl); }
.dialog.is-xl   { max-width: var(--container-5xl); }
.dialog.is-full { max-width: none; min-height: calc(100vh - 2 * var(--dialog-inset)); }

/* scroll="inside": the panel fits the viewport, the header and footer stay
   in view and the body scrolls. The body's padding keeps focus rings inside
   its scroll box; the negative margin keeps the layout where it was. */
.dialog.is-scroll-inside {
  max-height: calc(100dvh - 2 * var(--dialog-inset));
}

.dialog.is-scroll-inside > .dialog-body {
  flex:                1 1 auto;
  min-height:          0;
  overflow-y:          auto;
  overscroll-behavior: contain;
  margin:              calc(-1 * var(--space-1));
  padding:             var(--space-1);
}

/* A body that overflows is a Tab stop (dialog.ts, scrollFocus). */
.dialog-body:focus-visible {
  outline:    none;
  box-shadow: var(--focus-ring);
}

.dialog-header {
  display:            flex;
  flex-direction:     column;
  gap:                var(--space-1-5);
  padding-inline-end: var(--space-8);
}

.dialog-title {
  margin:         0;
  font-family:    var(--font-heading);
  font-size:      var(--text-title);
  font-weight:    var(--weight-strong);
  letter-spacing: var(--tracking-heading);
  line-height:    var(--leading-snug);
  color:          var(--ink);
}

.dialog-description {
  margin:      0;
  font-size:   var(--text-sm);
  line-height: var(--leading-body);
  color:       var(--ink-dim);
}

.dialog-body {
  display:        flex;
  flex-direction: column;
  gap:            var(--space-3);
}

.dialog-footer {
  display:         flex;
  flex-wrap:       wrap;
  justify-content: flex-end;
  gap:             var(--space-2);
}

/* .button sets position: relative at the same weight, and which stylesheet
   loads last differs page to page: the button class makes this one win. */
.dialog-close.button {
  position:         absolute;
  top:              calc(var(--dialog-padding) - var(--space-2));
  inset-inline-end: calc(var(--dialog-padding) - var(--space-2));
}

/* Motion */

.dialog-overlay[data-state="open"] {
  animation: dialog-overlay-in var(--duration-enter) var(--ease-enter);
}

.dialog-overlay[data-state="closed"] {
  animation: dialog-overlay-out var(--duration-exit) var(--ease-exit) forwards;
}

.dialog[data-state="open"] {
  animation: dialog-in var(--duration-enter) var(--ease-enter);
}

.dialog[data-state="closed"] {
  animation: dialog-out var(--duration-exit) var(--ease-exit) forwards;
}

@keyframes dialog-overlay-in  { from { opacity: 0; } }
@keyframes dialog-overlay-out { to   { opacity: 0; } }

@keyframes dialog-in {
  from {
    opacity:   0;
    transform: translateY(calc(var(--enter-distance) * 0.5)) scale(var(--enter-scale));
  }
}

@keyframes dialog-out {
  to {
    opacity:   0;
    transform: scale(var(--enter-scale));
  }
}

/* Phone */

@media (max-width: 40rem) {
  .dialog-overlay {
    --dialog-inset: var(--space-3);
  }

  .dialog-footer {
    flex-direction: column-reverse;
  }

  .dialog-footer > .button {
    width: 100%;
  }

  /* size="full" fills a small screen edge to edge (APG modal example). */
  .dialog-overlay:has(> .dialog.is-full) {
    --dialog-inset: 0px;
  }

  .dialog.is-full {
    min-height:    100dvh;
    border-radius: 0;
  }
}

}
