:root {
  --ee-speed: 0.3s;
  --ee-speed-slow: 0.5s;
  --ee-speed-fast: 0.2s;
  --ee-easing: ease;
  /* JS teardown delays — must cover the longest exit transition of each type */
  --ee-overlay-out: 0.5s;
  --ee-overlay-door-out: 0.6s;
  --ee-modal-out: 0.3s;
  --ee-cursor-close:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='9' fill='%23333333'/%3E%3Cline x1='6' y1='6' x2='14' y2='14' stroke='white' stroke-width='2' stroke-linecap='round'/%3E%3Cline x1='14' y1='6' x2='6' y2='14' stroke='white' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E")
      10 10,
    auto;
}

/* ── Push mode ───────────────────────────────────────────────────────────────
   Emerge marks the page container itself, so a consumer never has to remember
   to add a magic class to the element it already handed the constructor.

   Two markers, because a transform and its transition have different lifetimes:
     [data-ee-push-target]  persistent for the whole open→close cycle; carries
                            the transition. Removed only after the close
                            animation finishes, otherwise dropping it would take
                            the transition with it and the page would snap back.
     [data-ee-push="<dir>"] transient; carries the transform. Removed at the
                            start of close(), which is what animates the page
                            home again.

   The value is the direction the *page* travels, not the dialog. --dialog-width
   and --dialog-height are set on the container by Emerge (custom properties do
   not inherit upward from the dialog). */
[data-ee-push-target] {
  transition:
    transform var(--ee-speed) var(--ee-easing),
    filter var(--ee-speed) var(--ee-easing);
}
[data-ee-push="right"] {
  transform: translateX(var(--dialog-width));
}
[data-ee-push="left"] {
  transform: translateX(calc(-1 * var(--dialog-width)));
}
[data-ee-push="down"] {
  transform: translateY(var(--dialog-height));
}
[data-ee-push="up"] {
  transform: translateY(calc(-1 * var(--dialog-height)));
}

/* ── Dialog base ─────────────────────────────────────────────────────────── */

dialog {
  position: fixed;
  border: none;
  padding: 0;
  margin: 0;
  max-width: none;
  max-height: none;
  background-color: var(
    --bg-primary,
    var(--md-sys-color-surface-container-high, white)
  ); /* theme-aware — --bg-primary is never actually set anywhere in this
        app, so this fallback IS the real value every dialog gets; it used
        to be a bare "white" (always white, in every theme). Falls back to
        the app's own surface token instead, which already resolves per the
        active light/dark/data-auth theme (see planit.css) — and per-dialog
        overrides of that same token (e.g. tr-ref-viewer's Dark/Light
        buttons) still take effect too, since this rule just reads whatever
        value is in scope at each dialog element. */
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
  border-radius: 4px;
  transition:
    transform var(--ee-speed) var(--ee-easing),
    opacity var(--ee-speed) var(--ee-easing);
}

/* ── Backdrop — unified slide-in mechanism for all dialog types ──────────── */

dialog::backdrop {
  background: color-mix(
    in srgb,
    var(--bd-color, #000) calc(var(--bd-opacity, 0.5) * 100%),
    transparent
  );
  backdrop-filter: blur(var(--bd-blur, 0px));
  opacity: 1;
  transition: background var(--ee-speed) var(--ee-easing);
  cursor: var(--ee-cursor-close);
}
/* Suppress backdrop transition on re-open to prevent flash from mid-flight close transition */
dialog[data-bd-opening]::backdrop {
  transition: none !important;
}
/* Default: transparent before slide-in, and after slide-in removed on close */
dialog::backdrop {
  background: color-mix(in srgb, var(--bd-color, #000) 0%, transparent);
}
/* Active: fully visible when slide-in present */
dialog.slide-in::backdrop {
  background: color-mix(
    in srgb,
    var(--bd-color, #000) calc(var(--bd-opacity, 0.5) * 100%),
    transparent
  );
}
/* Blur: snap in instantly, fade out with background */
dialog[data-bd-blur]::backdrop {
  transition:
    background var(--ee-speed) var(--ee-easing),
    backdrop-filter 0s;
  backdrop-filter: blur(0px);
  background: color-mix(in srgb, var(--bd-color, #000) 0%, transparent);
}
dialog[data-bd-blur].slide-in::backdrop {
  backdrop-filter: blur(var(--bd-blur, 0px));
  background: color-mix(
    in srgb,
    var(--bd-color, #000) calc(var(--bd-opacity, 0.5) * 100%),
    transparent
  );
}
dialog[data-click-close="false"]::backdrop {
  cursor: default;
}
/* Closing: the surface is no longer interactive, so stop advertising the close affordance */
dialog.animate-out::backdrop {
  opacity: 0;
  transition: opacity var(--ee-speed, 0.3s) ease;
  cursor: default;
}
dialog[data-push-mode="true"]::backdrop {
  cursor: default;
}

/* ── Push mode ───────────────────────────────────────────────────────────── */

dialog[data-push-mode="true"] {
  z-index: 1000;
}

/* Push-mode uses a real <div> because ::backdrop only exists for showModal().
   It fades in/out on opacity (rather than background-color) so an optional
   backdrop-filter blur fades in lockstep instead of snapping. Emerge adds
   .slide-in at the same moment the dialog gets it, and removes the element
   in the same _closeTimeout that ends the dialog animation. */
[data-ee-push-backdrop] {
  position: fixed;
  inset: 0;
  z-index: 999;
  opacity: 0;
  transition: opacity var(--ee-speed) var(--ee-easing);
}
[data-ee-push-backdrop].slide-in {
  opacity: 1;
}

/* ── Flyout directions ───────────────────────────────────────────────────── */

dialog[data-direction="left"]:not([data-mode="notification"]) {
  left: var(--margin-left, 0px);
  top: var(--dialog-offset-v, var(--margin-top, 0px));
  width: var(--dialog-width);
  height: var(--dialog-height);
  max-width: 100%;
  max-height: 100dvh;
  right: auto;
  bottom: auto;
  transform: translateX(-100%);
  box-shadow: 2px 0 10px rgba(0, 0, 0, 0.3);
}
dialog[data-direction="left"]:not([data-mode="notification"]).slide-in {
  transform: translateX(0);
}

dialog[data-direction="right"]:not([data-mode="notification"]) {
  right: var(--margin-right, 0px);
  top: var(--dialog-offset-v, var(--margin-top, 0px));
  left: auto;
  bottom: auto;
  width: var(--dialog-width);
  height: var(--dialog-height);
  max-width: 100%;
  max-height: 100dvh;
  transform: translateX(100%);
  box-shadow: -2px 0 10px rgba(0, 0, 0, 0.3);
}
dialog[data-direction="right"]:not([data-mode="notification"]).slide-in {
  transform: translateX(0);
}

dialog[data-direction="top"]:not([data-mode="notification"]) {
  top: var(--margin-top, 0px);
  left: var(--dialog-offset-h, var(--margin-left, 0px));
  right: auto;
  bottom: auto;
  width: var(--dialog-width);
  height: var(--dialog-height);
  max-width: 100%;
  max-height: 100dvh;
  transform: translateY(-100%);
}
dialog[data-direction="top"]:not([data-mode="notification"]).slide-in {
  transform: translateY(0);
}

dialog[data-direction="bottom"]:not([data-mode="notification"]) {
  top: auto;
  bottom: var(--margin-bottom, 0px);
  left: var(--dialog-offset-h, var(--margin-left, 0px));
  right: auto;
  width: var(--dialog-width);
  height: var(--dialog-height);
  max-width: 100%;
  max-height: 100dvh;
  transform: translateY(100%);
}
dialog[data-direction="bottom"]:not([data-mode="notification"]).slide-in {
  transform: translateY(0);
}

dialog[data-direction]:not([data-mode="notification"]).animate-out {
  opacity: 0;
}

/* When reverseAnimation="fade" is set, suppress the directional
   transform on close so only the opacity transition is visible. */
dialog[data-reverse-animation="fade"].animate-out {
  transform: none !important;
}

/* ── Flyout animations: fade, scale ─────────────────────────────────────── */

dialog[data-animation="fade"] {
  opacity: 0;
}
dialog[data-animation="fade"].slide-in {
  opacity: 1;
}
dialog[data-animation="fade"][data-direction="left"],
dialog[data-animation="fade"][data-direction="right"],
dialog[data-animation="fade"][data-direction="top"],
dialog[data-animation="fade"][data-direction="bottom"] {
  transform: none;
}

dialog[data-animation="scale"] {
  transform: scale(0.85);
  opacity: 0;
}
dialog[data-animation="scale"].slide-in {
  transform: scale(1);
  opacity: 1;
}

/* ── Dialog inner layout ─────────────────────────────────────────────────── */

dialog[open] {
  display: flex;
  flex-direction: column;
}

/* Optional wrapper between dialog[open] and the header/body. Without a rule
   here it defaults to display:block / height:auto, which severs the flex
   chain: it shrink-wraps to content, and any `flex:1` child inside it (e.g. a
   Traverse .tv-container) becomes inert because its parent is not a flex
   container. That is the real cause of the "tv-container collapses to ~100px"
   symptom — not a limitation of CSS flex.

   Making it a pass-through flex item that fills its parent and establishes a
   column context for its children keeps `.dialog-header { flex-shrink:0 }` and
   `.dialog-body { flex:1; min-height:0 }` working whether or not the wrapper
   is present. Callers needing different behaviour (overlay mode, specific
   flyouts) already override this at higher specificity. */
.dialog-content {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.dialog-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px;
  flex-shrink: 0;
}
.dialog-title {
  flex: 1;
  font-size: 15px;
  font-weight: 600;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dialog-body {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  padding: 16px 20px;
}

/* ── Shared close-button base ─────────────────────────────────────────────
   .close-btn (flyout/dialog), .ee-dialog-close (notification/popover), and
   .overlay-close-btn (emerge_overlays.css) all share this round "×"
   affordance shape/behaviour — only size and colour differ per surface
   below. .ee-close (modal, emerge_modal.css) is deliberately NOT included:
   it follows the app's square icon-button convention (--icon-btn-bg), a
   different visual language on purpose, not an oversight. */
.close-btn,
.ee-dialog-close,
.overlay-close-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  flex-shrink: 0;
}

.close-btn {
  background: none;
  font-size: 30px;
  color: var(--ee-close-color, #666);
  margin: 0;
  margin-left: auto;
  width: 36px;
  height: 36px;
}
.close-btn:hover {
  background-color: var(--ee-close-hover-bg, #f0f0f0);
}

.notifications-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: #666;
  padding: 0;
  margin: 0;
  position: absolute;
  top: -12px;
  left: -8px;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  line-height: 1;
}
.notifications-btn:hover {
  background-color: #f0f0f0;
}

.type-indicator {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  flex-shrink: 0;
}

/* ── Notification ────────────────────────────────────────────────────────── */
/*
 * Uses the same slide-in/animate-out mechanism as flyouts.
 * showNotification sets data-direction to the CSS edge (top/bottom/left/right).
 * data-animation controls slide vs fade behaviour.
 */

dialog[data-mode="notification"] {
  width: var(--notification-width, 320px);
  max-width: calc(100% - 32px);
  max-height: 200px;
}

dialog[data-mode="notification"][data-position="top-left"] {
  top: 0;
  left: 0;
  right: auto;
  bottom: auto;
  margin: 16px;
}
dialog[data-mode="notification"][data-position="top-right"] {
  top: 0;
  right: 0;
  left: auto;
  bottom: auto;
  margin: 16px;
}
dialog[data-mode="notification"][data-position="top-center"] {
  top: 0;
  left: 0;
  right: 0;
  bottom: auto;
  margin: 16px auto;
}
dialog[data-mode="notification"][data-position="bottom-left"] {
  bottom: 0;
  left: 0;
  right: auto;
  top: auto;
  margin: 16px;
}
dialog[data-mode="notification"][data-position="bottom-right"] {
  bottom: 0;
  right: 0;
  left: auto;
  top: auto;
  margin: 16px;
}
dialog[data-mode="notification"][data-position="bottom-center"] {
  bottom: 0;
  left: 0;
  right: 0;
  top: auto;
  margin: 16px auto;
}
dialog[data-mode="notification"][data-position="left-center"] {
  left: 0;
  top: 0;
  bottom: 0;
  right: auto;
  margin: auto 16px;
}
dialog[data-mode="notification"][data-position="right-center"] {
  right: 0;
  top: 0;
  bottom: 0;
  left: auto;
  margin: auto 16px;
}

/* Slide: start off-screen; slide-in transitions to translate(0,0) via flyout direction rules */
dialog[data-mode="notification"][data-animation="slide"][data-direction="top"] {
  transform: translateY(-100%);
  opacity: 0;
}
dialog[data-mode="notification"][data-animation="slide"][data-direction="bottom"] {
  transform: translateY(100%);
  opacity: 0;
}
dialog[data-mode="notification"][data-animation="slide"][data-direction="left"] {
  transform: translateX(-100%);
  opacity: 0;
}
dialog[data-mode="notification"][data-animation="slide"][data-direction="right"] {
  transform: translateX(100%);
  opacity: 0;
}
dialog[data-mode="notification"][data-animation="slide"].slide-in {
  transform: translate(0, 0);
  opacity: 1;
}

/* Fade: opacity only, no transform */
dialog[data-mode="notification"][data-animation="fade"] {
  opacity: 0;
  transform: none;
}
dialog[data-mode="notification"][data-animation="fade"].slide-in {
  opacity: 1;
}

/* Exit: removing slide-in triggers backdrop fade; JS sets transform for slide exit */
dialog[data-mode="notification"].animate-out {
  opacity: 0;
}

/* Inner layout */
dialog[data-mode="notification"] .dialog-header {
  display: grid;
  grid-template-columns: 36px 1fr 36px;
  align-items: center;
  gap: 6px;
  /*padding: 10px 12px 8px;*/
  padding: 4px;
  margin-bottom: 0;
  position: static;
}
dialog[data-mode="notification"][data-no-indicator] .dialog-header {
  grid-template-columns: 0px 1fr 36px;
  gap: 0;
}
dialog[data-mode="notification"] .dialog-body {
  padding: 4px 12px 8px;
  font-size: 13px;
  color: #555;
}

/* ── Popover ─────────────────────────────────────────────────────────────── */

[data-ee-popover] {
  position: fixed;
  border: none;
  padding: 0;
  margin: 16px;
  border-radius: 8px;
  background: white;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.18);
  width: var(--notification-width, 320px);
  /* % of the initial containing block, NOT 100vw — vw (and dvw/svw/lvw) all
     include the scrollbar gutter, so calc(100vw - 32px) overshoots the visible
     width whenever a vertical scrollbar is present. A popover is non-modal, so
     scroll is never locked and the scrollbar is always there. This matches the
     documentElement.clientWidth the JS already prefers for anchor offsets. */
  max-width: calc(100% - 32px);
  flex-direction: column;
  overflow: hidden;
  opacity: 0;
  transition:
    opacity var(--ee-speed) var(--ee-easing),
    display var(--ee-speed) allow-discrete,
    overlay var(--ee-speed) allow-discrete;
}
[data-ee-popover]:popover-open {
  display: flex;
  opacity: 1;
}
@starting-style {
  [data-ee-popover]:popover-open {
    opacity: 0;
  }
}

[data-ee-popover][data-position="top-left"] {
  top: 0;
  left: 0;
  right: auto;
  bottom: auto;
  margin: 16px;
}
[data-ee-popover][data-position="top-right"] {
  top: 0;
  right: 0;
  left: auto;
  bottom: auto;
  margin: 16px;
}
[data-ee-popover][data-position="bottom-left"] {
  bottom: 0;
  left: 0;
  right: auto;
  top: auto;
  margin: 16px;
}
[data-ee-popover][data-position="bottom-right"] {
  bottom: 0;
  right: 0;
  left: auto;
  top: auto;
  margin: 16px;
}
[data-ee-popover][data-position="top-center"] {
  top: 0;
  left: 0;
  right: 0;
  bottom: auto;
  margin: 16px auto;
}
[data-ee-popover][data-position="bottom-center"] {
  bottom: 0;
  left: 0;
  right: 0;
  top: auto;
  margin: 16px auto;
}
[data-ee-popover][data-position="left-center"] {
  left: 0;
  top: 0;
  bottom: 0;
  right: auto;
  margin: auto 16px;
}
[data-ee-popover][data-position="right-center"] {
  right: 0;
  top: 0;
  bottom: 0;
  left: auto;
  margin: auto 16px;
}

/* Popover inner layout */
[data-ee-popover] .ee-dialog-header {
  display: grid;
  grid-template-columns: 36px 1fr 36px;
  align-items: center;
  gap: 6px;
  padding: 8px 10px 8px 4px;
}
[data-ee-popover][data-no-indicator] .ee-dialog-header {
  grid-template-columns: 0px 1fr 36px;
  gap: 0;
}
.ee-dialog-indicator {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.ee-dialog-title {
  grid-column: 2;
  font-size: 14px;
  font-weight: 600;
  margin: 0;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ee-dialog-close {
  width: 28px;
  height: 28px;
  background: none;
  color: #999;
  font-size: 18px;
  transition:
    background 0.15s,
    color 0.15s;
}
.ee-dialog-close:hover {
  background: #f0f0f0;
  color: #333;
}
.ee-dialog-body {
  padding: 4px 12px 10px;
  font-size: 13px;
  color: #555;
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  dialog,
  [data-ee-popover] {
    transition-duration: 0.01ms;
    animation-duration: 0.01ms;
  }
}
