body {
  font-family: system-ui, sans-serif;
  margin: 2rem;
}

.btn {
  padding: 0.5rem 1rem;
  border: 1px solid #888;
  border-radius: 999px;
  background: #fff;
  cursor: pointer;
}

dialog#modal {
  border: none;
  border-radius: 0.75rem;
  padding: 2rem;
  width: min(90vw, 26rem);
  box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.3);

  /* rest/closed state */
  opacity: 0;
  translate: 0 50px;
}

dialog#modal[open] {
  opacity: 1;
  translate: 0 0;
}

.close {
  float: right;
  border: none;
  background: none;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}

/* Same technique as starting-style-toast / starting-style-sidebar, on a
   native <dialog> instead of the checkbox hack: allow-discrete lets
   display/overlay (both discrete properties) participate in the
   transition at all, so closing fades out instead of vanishing instantly.
   @starting-style supplies the "from" state for OPENING — a display:none
   element has no previous box to transition from otherwise. Order matters:
   this block must come after the [open] rule (cascade/last-rule-wins), or
   opening won't animate.
   Kevin Powell, "Transitioning to and from display: none",
   https://www.youtube.com/watch?v=KD3_l3S_D6M — also demonstrates
   asymmetric enter/exit (different starting-style vs. rest translate) and
   fading ::backdrop, both used below. */
@media (prefers-reduced-motion: no-preference) {
  dialog#modal {
    transition: opacity 0.3s ease, translate 0.3s ease,
      display 0.3s allow-discrete, overlay 0.3s allow-discrete;
  }

  dialog#modal[open] {
    @starting-style {
      opacity: 0;
      /* enters from above, rest state (closed) exits downward — asymmetric */
      translate: 0 -50px;
    }
  }

  dialog#modal::backdrop {
    opacity: 0;
    transition: opacity 0.3s ease, display 0.3s allow-discrete, overlay 0.3s allow-discrete;
  }

  dialog#modal[open]::backdrop {
    opacity: 1;

    @starting-style {
      opacity: 0;
    }
  }
}
