/* When PageLayout owns scrolling, the body shouldn't reserve scrollbar gutter space.
   This prevents the right-side gap that body { overflow-y: scroll } would otherwise create. */
:global(body):has([data-contain-scrolling]) {
  overflow: hidden;
}

/* Root shell */
.root {
  width: 100%;
  max-width: 100%;
  display: grid;
  gap: 0;

  /* Banner height computed from its own tokens (not measured) — accurate for the
     built-in EnvironmentBanner; off by the difference for a custom-height banner. */
  --page-layout-banner-height: calc(
    var(--spacing-2xs) * 2 + var(--font-size-md) * var(--line-height-normal)
  );

  /* Structural bottom breathing room for all page content, so it doesn't sit
     flush against the viewport edge. */
  --page-layout-content-padding-bottom: var(--spacing-xl);
}

/* Viewport handling:
   - containScrolling => app-shell: lock to viewport and manage scroll in regions
   - documentScrolling => let page scroll normally
*/
.containScrolling {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

.documentScrolling {
  min-height: 100vh;
  min-height: 100dvh;
  overflow: visible;
}

/* Orientation layouts */
.vertical {
  grid-template-columns: auto minmax(0, 1fr);
}

.horizontal {
  grid-template-columns: minmax(0, 1fr);
}

/* Banner: spans both sidebar and main columns */
.banner {
  grid-column: 1 / -1;
  min-width: 0;
  flex: 0 0 auto;
}

/* Keep the banner visible while scrolling instead of it scrolling away; header and
   sidebar stick right below it (see their top offsets further down). */
.documentScrolling .banner {
  position: sticky;
  top: 0;
  z-index: calc(var(--z-sticky) + 1);
}

/* Give the banner its natural height, then the rest to the sidebar+main row (the
   `1fr` row grows beyond it if content needs more — the CSS-grid sticky-footer trick). */
.hasBanner {
  grid-template-rows: auto 1fr;
}

/* documentScrolling only has `min-height` (so long content can still grow the
   page), which leaves the grid container's own block-size indefinite — and an
   indefinite container makes the `1fr` row above size itself from its content
   (i.e. from the sidebar's own capped height below) instead of from real
   leftover viewport space. Any drift between --page-layout-banner-height's
   estimate and the banner's real rendered height then inflated the whole page,
   but only once the sidenav's content was tall enough to hit that cap — giving
   this one combination a real, definite block-size makes the `1fr` row's size
   come from the banner's actual rendered height, so the estimate is only ever
   used below as a cap, never as the page's actual size. */
.documentScrolling.vertical.hasBanner {
  height: 100vh;
  height: 100dvh;
}

/* Sidebar */
.sidebar {
  min-width: 0;
  min-block-size: 0; /* CRITICAL: else a tall sidenav grows the grid row instead of scrolling */
  overflow: hidden;
  background: var(--color-bg-surface);

  /* Hug the sidebar's own content width instead of stretching to fill the "auto"
     column — some browsers size that column wider than the content once a
     descendant scrollbar reserves space, leaving a visible gap otherwise. */
  justify-self: start;
}

/* The Sidebar/SidebarContainer inside already owns its own internal scrolling
   (its root is height:100%; overflow:auto). This wrapper only needs to cap the
   available height — if it *also* reserves its own scrollbar, that scrollbar's
   width gets folded into this box's max-content size (used by `justify-self:
   start` above), making it a scrollbar's-width wider than the fixed-width
   Sidebar inside and leaving a gap on the right edge. */
.containScrolling .sidebar {
  overflow: hidden;
}

/* Pin the sidebar to the viewport and let it scroll independently of the document.
   max-block-size is a hard cap: a grid row's "auto" size still grows to fit a long
   sidenav's content otherwise (min-block-size: 0 alone doesn't stop that). */
.documentScrolling.vertical .sidebar {
  position: sticky;
  top: 0;
  max-block-size: 100vh;
  max-block-size: 100dvh;
  /* See the .containScrolling .sidebar comment above — same double-scrollbar
     reasoning applies here. */
  overflow: hidden;
}

/* Leave room for the banner's height, and stick below it instead of at top:0 so it
   doesn't slide up underneath the now-sticky banner while scrolling. */
.documentScrolling.vertical.hasBanner .sidebar {
  top: var(--page-layout-banner-height);
  max-block-size: calc(100vh - var(--page-layout-banner-height));
  max-block-size: calc(100dvh - var(--page-layout-banner-height));
}

/* Without a banner, the sidebar is the grid's only row (sizes to content, doesn't
   stretch), so it needs an explicit height. With a banner, it stretches to fill the
   `1fr` row instead (see .hasBanner above). */
.documentScrolling.vertical:not(.hasBanner) .sidebar {
  align-self: start;
  block-size: 100vh;
  block-size: 100dvh;
}

/* In horizontal orientation, sidebar becomes a full-width top block if used */
.horizontal .sidebar {
  grid-column: 1 / -1;
  justify-self: stretch;
  border-right: none;
  border-bottom: var(--border-width-thin) solid var(--color-border-subtle);
}

/* Main column:
   Use flex so the "rest of space" logic works reliably.
*/
.mainColumn {
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--color-bg-surface);
}

/* In containScrolling mode, mainColumn must fill the viewport height
   so the flex "remaining space" can be computed.
*/
.containScrolling .mainColumn {
  height: 100%;
  min-height: 0; /* important: allows children to shrink */
}

/* Regions */
.header {
  min-width: 0;
  background: var(--color-navbar-bg);
  border-bottom: var(--border-width-thin) solid var(--color-border-default);
  flex: 0 0 auto;
}

/* Sticky header only when the document is scrolling (body scroll) */
.documentScrolling .header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
}

/* Stick right below the (also sticky) banner instead of underneath it. */
.documentScrolling.hasBanner .header {
  top: var(--page-layout-banner-height);
}

.hero {
  min-width: 0;
  background: var(--color-bg-surface);
  border-bottom: var(--border-width-thin) solid var(--color-border-subtle);
  flex: 0 0 auto;
}

/* Scroll wrapper: contains content + footer */
.mainScroll {
  min-width: 0;
  min-height: 0; /* CRITICAL for nested flex/scroll */
  display: flex;
  flex-direction: column;

  /* This is the "take all remaining space" bit */
  flex: 1 1 auto;

  /* default: documentScrolling uses normal page flow */
  overflow: visible;
}

/* Contained scrolling: mainScroll scrolls (includes footer) */
.containScrolling .mainScroll {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

/* Content area (not a scroll container anymore) */
.content {
  min-width: 0;
  /* Deliberately no min-height:0 here (unlike `.mainScroll` above, which does
     need it): this lets `.content` size to its own natural content height —
     including its own padding-block-end — instead of being flex-shrunk
     shorter than that content. `.mainScroll` (overflow:auto) already has its
     own min-height:0, which is what lets it stay bounded to the available
     space and scroll; if `.content` could *also* shrink below its content,
     that shrunk-but-visible-overflow content would spill straight past
     wherever its own bottom padding was supposed to land, so it would never
     actually render (this happened in practice before this comment existed). */
  flex: 1 1 auto; /* take remaining space inside mainScroll */
  display: flex; /* lets contentInner stretch */
  flex-direction: column;
  align-items: center;

  background: var(--color-bg-surface);
  padding-block-start: var(--spacing-md);
  padding-inline: var(--spacing-md);
  padding-block-end: calc(
    var(--page-layout-content-padding-bottom) + env(safe-area-inset-bottom, 0px)
  );
  overflow: visible;
}

.horizontal .content {
  padding-top: var(--spacing-lg);
  padding-inline: var(--spacing-lg);
}

.footer {
  min-width: 0;
  background: var(--color-bg-surface-subtle);
  display: flex;
  justify-content: center;
  padding-inline: var(--spacing-md);

  /* When there is extra space (content is short), this pushes footer to the bottom.
     When content is long, footer follows content normally and is reached by scrolling.
  */
  margin-top: auto;
  flex: 0 0 auto;
}

.horizontal .footer {
  padding-inline: var(--spacing-lg);
}

/* Header slot wrappers */
.headerContainer {
  display: flex;
  justify-content: center;
  width: 100%;
  padding-inline: var(--spacing-md);
}

.horizontal .headerContainer {
  padding-inline: var(--spacing-lg);
}

.headerContent {
  width: 100%;
  box-sizing: border-box;
}

.footerContent {
  width: 100%;
  box-sizing: border-box;
}

.maxWidthMd {
  max-width: 1600px;
  margin-inline: auto;
  width: 100%;
  box-sizing: border-box;
}

.maxWidthSm {
  margin-inline: auto;
  width: 100%;
  box-sizing: border-box;
}

@media (min-width: 640px) {
  .maxWidthSm {
    max-width: 640px;
  }
}

@media (min-width: 768px) {
  .maxWidthSm {
    max-width: 668px;
  }
}

@media (min-width: 1024px) {
  .maxWidthSm {
    max-width: 924px;
  }
}

@media (min-width: 1280px) {
  .maxWidthSm {
    max-width: 1180px;
  }
}

/* Content slot inner wrapper (so maxWidth works without interfering with scroll) */
.contentInner {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xl);
  width: 100%;
  box-sizing: border-box;
  min-width: 0;

  /* This is what makes your "main content" actually expand to fill */
  flex: 1 1 auto;
  min-height: 0;
}

/* Optional: for small viewport heights, avoid forced viewport locking */
@media (max-height: 400px) {
  .containScrolling {
    height: auto;
    overflow: visible;
  }

  /* In this mode, avoid forcing a nested scroll region */
  .containScrolling .mainScroll {
    overflow: visible;
  }

  .containScrolling .mainColumn {
    height: auto;
  }
}
