@layer components {
  /* Popovers — a surface anchored to the control that opened it.
   *
   * The same <dialog> and the same dialog_controller as a modal, opened with
   * modal: false. That is the whole difference: a modal takes the top layer and
   * the operator's whole attention, a popover belongs to one control and leaves
   * the page alone. Nothing else about how an overlay behaves is decided twice.
   *
   * Placement is still CSS — which side it opens on, what the opposite side is,
   * and how far off its anchor it sits are all below. What changed is where the
   * anchor's edges come from: anchoring_helpers measures them and writes
   * --anchor-below, --anchor-above, --anchor-start, --anchor-end and
   * --anchor-width, and these rules spend them. The helper knows nothing about
   * sides, which is how one function serves a menu opening downward and a picker
   * opening upward.
   *
   * **position: fixed, and that is the whole point of it.** This was
   * `position: absolute` against the wrapper, which is tidier and has one fatal
   * property: an absolutely positioned box is clipped by any ancestor that
   * scrolls or hides its overflow, and this app has eight of those. A row-actions
   * menu on the last row of a `.panel--flush` table was cut off at the bottom of
   * the table; a combobox at the foot of a `.dialog__body` could not be read at
   * all. Half of those ancestors must scroll, so no arrangement of the markup
   * fixed it. A fixed box's containing block is the viewport and nothing clips
   * it.
   *
   * What that costs, and it is the only thing: the surface no longer follows its
   * anchor for free, so the helper re-places it on scroll and on resize while it
   * is open. It also means an ancestor with a transform, a filter or `contain`
   * would capture it — there is none on any path to one of these today, and a
   * new one would show up as a surface that suddenly clips again.
   */
  .popover {
    --popover-width: max-content;
    --popover-min-width: 12rem;
    --popover-max-width: 20rem;
    --popover-max-height: 60dvh;
    --popover-offset: var(--space-quarter);
    --popover-padding: var(--space-half);
    --popover-radius: var(--radius);
    --popover-duration: var(--duration);

    position: relative;
    display: inline-flex;
  }

  .popover__surface {
    position: fixed;
    z-index: var(--z-popup);
    inset-block: var(--anchor-below) auto;
    inset-inline: var(--anchor-start) auto;

    /* The gap between the surface and its anchor, as a margin rather than folded
       into the inset — so the helper writes an edge and only this file decides
       how far off it to sit. margin-inline is spelled out because a <dialog>'s
       own margin is auto, which with one inline inset set resolves to nothing
       useful. */
    margin-block: var(--popover-offset) 0;
    margin-inline: 0;
    padding: var(--popover-padding);
    border: var(--border);
    border-radius: var(--popover-radius);
    background: var(--color-canvas);
    color: var(--color-ink);
    box-shadow: var(--shadow-overlay);
    inline-size: var(--popover-width);
    min-inline-size: var(--popover-min-width);
    max-inline-size: min(var(--popover-max-width), calc(100dvw - var(--space-double)));
    max-block-size: var(--popover-max-height);
    overflow: auto;
    overscroll-behavior: contain;
    translate: var(--orient-shift);

    /* Opacity, and deliberately nothing that moves it.
     *
     * The helper measures this surface the instant it opens, and a transform in
     * flight is a lie about where it is: with a scale on the way in, every
     * measurement comes back a few per cent small and a surface that should
     * have flipped decides it fits. A popover appears next to its trigger
     * anyway, which is a short enough distance that a fade is the whole
     * gesture. */
    opacity: 0;
    transition-property: display, opacity;
    transition-duration: var(--popover-duration);
    transition-timing-function: var(--ease-out);
    transition-behavior: allow-discrete;

    /* display is the only property that may be conditional on [open] — see
       dialog.css, which has the scars. opacity is transitioned, so it is safe
       here; anything that isn't would snap back the moment the attribute went. */
    &[open] {
      display: block;
      opacity: 1;
    }

    @starting-style {
      &[open] {
        opacity: 0;
      }
    }

    /* Flipped, because the surface would otherwise open off the edge of the
       window. The helper decides that by measuring; what a flip *means* is
       here, which is why the same helper serves a menu and a tooltip. */
    &[data-anchor-block="flip"] {
      inset-block: auto var(--anchor-above);
      margin-block: 0 var(--popover-offset);
    }

    &[data-anchor-inline="flip"] {
      inset-inline: auto var(--anchor-end);
    }
  }

  /* Variants */

  /* Aligned to the trigger's end edge, for a popover hung off something at the
     end of a row — a row action, the last control in a toolbar. */
  .popover--end .popover__surface {
    inset-inline: auto var(--anchor-end);

    &[data-anchor-inline="flip"] {
      inset-inline: var(--anchor-start) auto;
    }
  }

  /* Opens upward. For a trigger that lives at the bottom of the screen, where
     down is the wrong first guess rather than a fallback. */
  .popover--above .popover__surface {
    inset-block: auto var(--anchor-above);
    margin-block: 0 var(--popover-offset);

    &[data-anchor-block="flip"] {
      inset-block: var(--anchor-below) auto;
      margin-block: var(--popover-offset) 0;
    }
  }

  .popover--wide {
    --popover-max-width: 28rem;
  }

  /* Fills its container rather than hugging its trigger, for a popover whose
     trigger is a whole row — the account switcher at the head of the sidebar. */
  .popover--block {
    display: flex;
  }

  /* For a surface that brings its own padding — a list, a form with its own
     gutters. */
  .popover--flush {
    --popover-padding: 0;
  }

  .popover__title {
    margin: 0 0 var(--space-half);
    font-size: var(--text-normal);
    font-weight: var(--weight-bold);
  }

  /* .popover__footer is in footer.css, with the other three. */

  @media (prefers-reduced-motion: reduce) {
    .popover__surface {
      transition-duration: 0s;
    }
  }
}
