/* === Bootstrap-style scaffold (transparent full-viewport <dialog>) === */
dialog.turbo-overlay-scaffold {
  border: 0; padding: 0; margin: 0; background: transparent;
  max-width: none; max-height: none;
}
dialog.turbo-overlay-scaffold::backdrop { background: rgba(0, 0, 0, 0.5); }
dialog.turbo-overlay-scaffold.turbo-overlay--modal {
  width: 100%; height: 100%; overflow-y: auto;
}
dialog.turbo-overlay-scaffold.turbo-overlay--drawer { overflow: hidden; }
dialog.turbo-overlay-scaffold.turbo-overlay--drawer-right  { inset: 0 0 0 auto; height: 100vh; width: 400px; max-width: 100vw; }
dialog.turbo-overlay-scaffold.turbo-overlay--drawer-left   { inset: 0 auto 0 0; height: 100vh; width: 400px; max-width: 100vw; }
dialog.turbo-overlay-scaffold.turbo-overlay--drawer-top    { inset: 0 0 auto 0; width: 100vw; max-height: 50vh; }
dialog.turbo-overlay-scaffold.turbo-overlay--drawer-bottom { inset: auto 0 0 0; width: 100vw; max-height: 50vh; }
dialog.turbo-overlay-scaffold .offcanvas {
  position: static; visibility: visible; transform: none;
  width: 100%; height: 100%; max-width: none; max-height: none;
}
dialog.turbo-overlay-scaffold .turbo-drawer-panel {
  margin: 0; border-radius: 0; height: 100%; display: flex; flex-direction: column;
  border: 0; box-shadow: 0 0 30px rgba(0, 0, 0, 0.15);
}
dialog.turbo-overlay-scaffold .turbo-drawer-body { flex: 1; overflow-y: auto; }

/* === Plain theme ===
   Baseline dialog visuals are wrapped in `:where()` so they have
   zero specificity. The plain theme partials (which only set the
   `.turbo-modal` / `.turbo-drawer` / `.turbo-popover` class) still
   pick them up, but tailwind/bootstrap themes that add their own
   classes to the dialog (e.g. `bg-white dark:bg-gray-800`) win
   without a specificity battle — regardless of which stylesheet
   loads later in the cascade.
*/
:where(dialog.turbo-modal) {
  border: 0; padding: 0; border-radius: 8px;
  max-width: 32rem; width: 90vw;
  max-height: 90vh;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);
}
:where(dialog.turbo-modal)::backdrop { background: rgba(0, 0, 0, 0.5); }
.turbo-modal__content { display: flex; flex-direction: column; max-height: 90vh; position: relative; }
.turbo-modal__header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.25rem; border-bottom: 1px solid #e5e7eb;
  flex-shrink: 0;
}
.turbo-modal__title { margin: 0; font-size: 1.125rem; font-weight: 600; }
.turbo-modal__close { background: none; border: 0; font-size: 1.5rem; cursor: pointer; line-height: 1; }
.turbo-modal__close:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 2px; }
.turbo-modal__close--floating { position: absolute; top: 0.5rem; right: 0.75rem; z-index: 1; }
.turbo-modal__body { padding: 1.25rem; flex: 1; overflow-y: auto; }
.turbo-modal__footer {
  padding: 1rem 1.25rem; border-top: 1px solid #e5e7eb;
  display: flex; justify-content: flex-end; gap: 0.5rem;
  flex-shrink: 0;
}

:where(dialog.turbo-drawer) {
  border: 0; padding: 0; margin: 0; background: white;
  box-shadow: 0 0 30px rgba(0, 0, 0, 0.15);
  max-width: 100vw; max-height: 100vh;
}
:where(dialog.turbo-drawer)::backdrop { background: rgba(0, 0, 0, 0.5); }
:where(dialog.turbo-drawer.turbo-overlay--drawer-right)  { inset: 0 0 0 auto; height: 100vh; width: 24rem; }
:where(dialog.turbo-drawer.turbo-overlay--drawer-left)   { inset: 0 auto 0 0; height: 100vh; width: 24rem; }
:where(dialog.turbo-drawer.turbo-overlay--drawer-top)    { inset: 0 0 auto 0; width: 100vw; max-height: 50vh; }
:where(dialog.turbo-drawer.turbo-overlay--drawer-bottom) { inset: auto 0 0 0; width: 100vw; max-height: 50vh; }
.turbo-drawer__content { display: flex; flex-direction: column; height: 100%; position: relative; }
.turbo-drawer__header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.25rem; border-bottom: 1px solid #e5e7eb;
}
.turbo-drawer__title { margin: 0; font-size: 1.125rem; font-weight: 600; }
.turbo-drawer__close { background: none; border: 0; font-size: 1.5rem; cursor: pointer; line-height: 1; }
.turbo-drawer__close:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 2px; }
.turbo-drawer__close--floating { position: absolute; top: 0.5rem; right: 0.75rem; z-index: 1; }
.turbo-drawer__body { padding: 1.25rem; flex: 1; overflow-y: auto; }
.turbo-drawer__footer {
  padding: 1rem 1.25rem; border-top: 1px solid #e5e7eb;
  display: flex; justify-content: flex-end; gap: 0.5rem;
}

/* === Popover (anchored to trigger, non-modal) === */
:where(dialog.turbo-popover) {
  border: 0; padding: 0; margin: 0; background: white;
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  max-width: 22rem; max-height: 80vh; overflow: auto;
}
/* Popovers opened from inside an open modal dialog use showModal()
   themselves to avoid the parent modal's inertness blocking them.
   Make the resulting ::backdrop transparent so they still look like
   anchored popovers, not modals. The :modal pseudo matches only when
   entered via showModal. */
dialog.turbo-overlay--popover:modal::backdrop { background: transparent; }
.turbo-popover__content { display: flex; flex-direction: column; position: relative; }
.turbo-popover__header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.5rem 0.75rem; border-bottom: 1px solid #e5e7eb;
}
.turbo-popover__title { margin: 0; font-size: 0.95rem; font-weight: 600; }
.turbo-popover__close { background: none; border: 0; font-size: 1.25rem; cursor: pointer; line-height: 1; }
.turbo-popover__close:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 2px; }
.turbo-popover__close--floating { position: absolute; top: 0.25rem; right: 0.5rem; z-index: 1; }
.turbo-popover__body { padding: 0.75rem; }
.turbo-popover__footer {
  padding: 0.5rem 0.75rem; border-top: 1px solid #e5e7eb;
  display: flex; justify-content: flex-end; gap: 0.5rem;
}

/* === Hint (hover-triggered preview, non-modal, non-dialog) === */
/* Structural rules apply to every hint regardless of theme — JS sets
   top/left via the same anchor math as the popover, and the
   animation/closing classes drive the fade in/out. */
.turbo-overlay-hint {
  position: fixed; z-index: 1000;
  pointer-events: auto;
}
.turbo-overlay-hint[data-state="entering"] { animation: turbo-overlay-fade-in 0.12s ease-out; }
.turbo-overlay-hint[data-state="leaving"]  { animation: turbo-overlay-fade-out 0.12s ease-out forwards; }

/* Plain-theme visuals — opt in by adding `turbo-hint` to the chrome
   partial. The tailwind/bootstrap themes drop this class so their
   own utility classes drive background/border/shadow without
   collisions with the gem's plain defaults. (Tailwind v4 wraps its
   utilities in `@layer utilities`; the gem's CSS is unlayered, which
   wins over any layered rule regardless of specificity — including
   `:where()`. Separating classes is the only reliable fix.) */
.turbo-hint {
  max-width: 20rem; padding: 0.75rem 1rem;
  background: white;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
  font-size: 0.875rem;
}

/* === Animations (apply to every theme via shared classes) === */
dialog.turbo-overlay--modal[open]                            { animation: turbo-overlay-fade-in 0.15s ease-out; }
dialog.turbo-overlay--modal[open]::backdrop                  { animation: turbo-overlay-backdrop-in 0.15s ease-out; }
dialog.turbo-overlay--modal.turbo-overlay-closing            { animation: turbo-overlay-fade-out 0.15s ease-out forwards; }
dialog.turbo-overlay--modal.turbo-overlay-closing::backdrop  { animation: turbo-overlay-backdrop-out 0.15s ease-out forwards; }

dialog.turbo-overlay--drawer-right[open]                       { animation: turbo-overlay-slide-in-right 0.3s ease-out; }
dialog.turbo-overlay--drawer-left[open]                        { animation: turbo-overlay-slide-in-left 0.3s ease-out; }
dialog.turbo-overlay--drawer-top[open]                         { animation: turbo-overlay-slide-in-top 0.3s ease-out; }
dialog.turbo-overlay--drawer-bottom[open]                      { animation: turbo-overlay-slide-in-bottom 0.3s ease-out; }
dialog.turbo-overlay--drawer[open]::backdrop                   { animation: turbo-overlay-backdrop-in 0.3s ease-out; }
dialog.turbo-overlay--drawer-right.turbo-overlay-closing       { animation: turbo-overlay-slide-out-right 0.3s ease-out forwards; }
dialog.turbo-overlay--drawer-left.turbo-overlay-closing        { animation: turbo-overlay-slide-out-left 0.3s ease-out forwards; }
dialog.turbo-overlay--drawer-top.turbo-overlay-closing         { animation: turbo-overlay-slide-out-top 0.3s ease-out forwards; }
dialog.turbo-overlay--drawer-bottom.turbo-overlay-closing      { animation: turbo-overlay-slide-out-bottom 0.3s ease-out forwards; }
dialog.turbo-overlay--drawer.turbo-overlay-closing::backdrop   { animation: turbo-overlay-backdrop-out 0.3s ease-out forwards; }

/* Popovers position themselves by writing `transform: translate(...)`
   so the placement stays in sync with compositor-thread scroll. The
   open/close keyframes also use `transform`, so we set
   `animation-composition: add` on the dialog — keyframe transforms
   then compose with (rather than replace) the positioning transform. */
dialog.turbo-overlay--popover                        { animation-composition: add; }
dialog.turbo-overlay--popover:popover-open           { animation: turbo-overlay-popover-in  0.12s ease-out; }
dialog.turbo-overlay--popover.turbo-overlay-closing  { animation: turbo-overlay-popover-out 0.12s ease-out forwards; }

@keyframes turbo-overlay-fade-in     { from { opacity: 0; transform: scale(0.97); } to { opacity: 1; transform: scale(1); } }
@keyframes turbo-overlay-fade-out    { from { opacity: 1; transform: scale(1); }    to { opacity: 0; transform: scale(0.97); } }
@keyframes turbo-overlay-backdrop-in  { from { background: rgba(0,0,0,0); }   to { background: rgba(0,0,0,0.5); } }
@keyframes turbo-overlay-backdrop-out { from { background: rgba(0,0,0,0.5); } to { background: rgba(0,0,0,0); } }
@keyframes turbo-overlay-slide-in-right  { from { transform: translateX(100%); }  to { transform: translateX(0); } }
@keyframes turbo-overlay-slide-in-left   { from { transform: translateX(-100%); } to { transform: translateX(0); } }
@keyframes turbo-overlay-slide-in-top    { from { transform: translateY(-100%); } to { transform: translateY(0); } }
@keyframes turbo-overlay-slide-in-bottom { from { transform: translateY(100%); }  to { transform: translateY(0); } }
@keyframes turbo-overlay-slide-out-right  { from { transform: translateX(0); } to { transform: translateX(100%); } }
@keyframes turbo-overlay-slide-out-left   { from { transform: translateX(0); } to { transform: translateX(-100%); } }
@keyframes turbo-overlay-slide-out-top    { from { transform: translateY(0); } to { transform: translateY(-100%); } }
@keyframes turbo-overlay-slide-out-bottom { from { transform: translateY(0); } to { transform: translateY(100%); } }
@keyframes turbo-overlay-popover-in   { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
@keyframes turbo-overlay-popover-out  { from { opacity: 1; transform: translateY(0); }    to { opacity: 0; transform: translateY(-4px); } }

@media (prefers-reduced-motion: reduce) {
  dialog.turbo-overlay,
  dialog.turbo-overlay::backdrop,
  dialog.turbo-overlay.turbo-overlay-closing,
  dialog.turbo-overlay.turbo-overlay-closing::backdrop,
  .turbo-overlay-hint[data-state] { animation: none !important; }
}

/* === Loading state (cloned client-side while a request is in flight) === */
/* Wrapped in :where() so themes that drop their own classes on the
   loading partial win without specificity battles. */
:where(.turbo-overlay-loading__body) {
  display: flex; align-items: center; justify-content: center;
  min-height: 8rem; padding: 2rem;
}
:where(.turbo-overlay-loading__spinner) {
  display: inline-block;
  width: 1.5rem; height: 1.5rem;
  border: 3px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  opacity: 0.6;
  animation: turbo-overlay-loading-spin 0.8s linear infinite;
}
:where(.turbo-overlay-loading__sr-only) {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
@keyframes turbo-overlay-loading-spin { to { transform: rotate(360deg); } }

/* Drawer loading should fill its panel rather than rely on min-height. */
:where(dialog.turbo-overlay--drawer.turbo-overlay--loading .turbo-overlay-loading__body) {
  min-height: 100%;
}

/* Hint loading sits inside a tooltip-sized chrome — collapse the body's
   default min-height/padding so the spinner doesn't bloat the hint. */
:where(.turbo-overlay-hint.turbo-overlay--loading .turbo-overlay-loading__body) {
  min-height: 0;
  padding: 0;
}

@media (prefers-reduced-motion: reduce) {
  .turbo-overlay-loading__spinner { animation: none !important; }
}

/* === Non-modal drawer (opened via dialog.show(), no ::backdrop) === */
/* Non-modal <dialog> defaults to position: absolute (anchored to the
   document), which breaks the side-pinned inset rules above. Force
   fixed so the drawer stays anchored to the viewport. */
dialog.turbo-overlay--no-backdrop { position: fixed; }

/* === Scroll lock when any modal overlay is open === */
/* Skip non-backdrop drawers — they're meant to coexist with page
   interaction, including scrolling. */
html:has(dialog.turbo-overlay[open]:not(.turbo-overlay--no-backdrop)) { overflow: hidden; }
