/* Shared document freeze for every accessible modal.
   The document remains in its original formatting context: changing the body
   to position:fixed would recalculate fixed/sticky descendants and dvh-based
   sections, especially in iOS/PWA WebKit. */
html.studiverse-modal-scroll-locked {
  overflow: hidden !important;
  overscroll-behavior: none !important;
}

body.studiverse-modal-scroll-locked {
  overscroll-behavior: none !important;
}

/* Classic desktop scrollbars consume layout width. Retain that gutter only
   when it existed before the modal opened, so the page and fixed chrome keep
   their exact pre-modal geometry. */
html.studiverse-modal-scroll-locked.studiverse-modal-scrollbar-gutter {
  scrollbar-gutter: stable !important;
}

/* Old engines without scrollbar-gutter support keep the captured layout
   width. Modern engines take the branch above, which also preserves fixed
   descendants whose containing block is the viewport. */
html.studiverse-modal-scroll-locked.studiverse-modal-scrollbar-fallback {
  inline-size: var(
    --studiverse-modal-layout-width,
    calc(100vw - var(--studiverse-modal-scrollbar-width, 0px))
  ) !important;
  max-inline-size: var(
    --studiverse-modal-layout-width,
    calc(100vw - var(--studiverse-modal-scrollbar-width, 0px))
  ) !important;
}

[aria-modal="true"] {
  overscroll-behavior: contain;
}

/* Programmatic focus belongs on these non-interactive surfaces while the
   content behind them is covered. Chromium/Android can match :focus-visible
   and paint a viewport-sized ring; theme rules also style every [tabindex].
   Match only the surface itself, never its descendants or arbitrary tabindex
   targets (quiz options, tabs and scrollable content still need their cues).
   Keep decorative borders/shadows, focus ownership and text selection intact. */
html:root body :is(
  dialog,
  :is(div, section, article, aside)[role="dialog"][tabindex="-1"],
  :is(div, section, article, aside)[role="alertdialog"][tabindex="-1"],
  .path-arrival[tabindex="-1"],
  .path-adaptation[tabindex="-1"],
  #learningPathPrimaryContent[tabindex="-1"],
  #theoryReflectionDialog[tabindex="-1"]
):not([contenteditable]):focus {
  outline: none !important;
}
