@use 'sass:map';

@use '../config' as *;

@mixin navbar-vertical-nav {
  // Applies to every navbar-nav in the vertical navbar — the menu inside
  // .navbar-collapse and e.g. a .navbar-footer list outside of it.
  .navbar-nav {
    // Sidebar icons carry more meaning than inline tab icons, so they get
    // stronger contrast than the global 50% $nav-link-icon-color. Derived
    // from --navbar-color, which is defined at this scope (unlike
    // --nav-link-color, which only exists inside .nav).
    --nav-link-icon-color: #{color-transparent(var(--navbar-color), 0.7)};
    --nav-link-icon-width: #{$sidebar-nav-icon-width};
    --nav-link-icon-height: #{$sidebar-nav-icon-height};
    --sidebar-inset: #{$sidebar-inset};
    --sidebar-nav-padding-y: #{$sidebar-nav-padding-y};
    --sidebar-nav-padding-x: #{$sidebar-nav-padding-x};
    --sidebar-nav-indent: #{$sidebar-nav-indent};
    --sidebar-section-title-font-size: #{$sidebar-section-title-font-size};
    --sidebar-section-title-margin-top: #{$sidebar-section-title-margin-top};
    // Inset the list so the rounded hover/active pills never touch the
    // sidebar edges. The same inset and link padding apply in the folded
    // state, so icons keep their exact position when the sidebar folds.
    padding-inline: var(--sidebar-inset);
    margin-inline-start: 0;
    margin-inline-end: 0;

    .nav-link {
      justify-content: start;
      padding: var(--sidebar-nav-padding-y) var(--sidebar-nav-padding-x);
    }

    // One line, ellipsized — a title never wraps, so rows keep their height
    // while the folding sidebar animates its width.
    .nav-link-title {
      min-width: 0;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    // stylelint-disable-next-line selector-max-class
    .nav-item.active > .nav-link {
      --nav-link-icon-color: currentColor;
      font-weight: var(--font-weight-medium);
      background: var(--navbar-active-bg);
    }

    // A group that only holds the current page is emphasized, not filled: the
    // pill marks the page itself, and painting the group with the same pill
    // reads as two selections. The folded rail puts it back — there the titles
    // are collapsed and the submenu is a flyout, so the pill is the only thing
    // left that can point at the group.
    // stylelint-disable-next-line selector-max-class
    .nav-item.active > .nav-link.dropdown-toggle {
      background: transparent;
    }

    // Group label — aligned with the item text, muted like the icons.
    .nav-section-title {
      display: block;
      padding: 0.25rem var(--sidebar-nav-padding-x);
      margin-top: var(--sidebar-section-title-margin-top);
      font-size: var(--sidebar-section-title-font-size);
      font-weight: var(--font-weight-medium);
      color: #{color-transparent(var(--navbar-color), 0.7)};
      text-transform: uppercase;
      letter-spacing: 0.04em;

      &:first-child {
        margin-top: 0;
      }
    }
  }

  // .navbar-side wraps the menu's trailing group (a Customize link, a help
  // link) in its own .navbar-nav. The base rule lays it out as a row for the
  // horizontal navbar; here it stacks like the menu, never grows, and the
  // auto margin pins it to the bottom of the scroll area when the menu is
  // shorter than the sidebar.
  .navbar-side {
    flex-grow: 0;
    flex-direction: column;
    align-items: stretch;
    justify-content: start;
    padding-bottom: 0.25rem;
    margin-top: auto;

    .navbar-nav {
      flex-grow: 0;
    }
  }

  .navbar-collapse {
    flex-direction: column;

    [class^='container'] {
      flex-direction: column;
      align-items: stretch;
      padding: 0;
    }

    .dropdown-menu-columns {
      flex-direction: column;
    }

    .dropdown-menu {
      position: static;
      min-width: 0;
      padding: 0;
      margin: 0;
      color: inherit;
      background: transparent;
      border: none;
      box-shadow: none;

      .dropdown-item {
        display: flex;
        width: auto;
        min-width: 0;
        // Link padding + the icon column — items align with the parent
        // link's title, whatever the icon size and paddings are set to.
        padding-inline-start: calc(var(--sidebar-nav-padding-x) + var(--nav-link-icon-width) + var(--nav-link-icon-margin-end));
        color: inherit;
        @include border-radius(var(--border-radius));

        &.disabled {
          color: var(--disabled-color);
          pointer-events: none;
          background-color: transparent;
        }

        &.active,
        &:active {
          font-weight: var(--font-weight-medium);
          background: var(--navbar-active-bg);
        }
      }

      .dropdown-menu .dropdown-item {
        padding-inline-start: calc(var(--sidebar-nav-padding-x) + var(--nav-link-icon-width) + var(--nav-link-icon-margin-end) + var(--sidebar-nav-indent));
      }

      // Third-level submenu in the mobile vertical navbar — genuinely nested two
      // dropdown-menu levels deep.
      // stylelint-disable-next-line selector-max-class, selector-max-compound-selectors
      .dropdown-menu .dropdown-menu .dropdown-item {
        padding-inline-start: calc(var(--sidebar-nav-padding-x) + var(--nav-link-icon-width) + var(--nav-link-icon-margin-end) + 2 * var(--sidebar-nav-indent));
      }
    }

    .dropdown-toggle::after {
      margin-inline-start: auto;
    }

    // The active pill is the selection indicator — no underline or edge bar.
    .nav-item.active::after {
      content: none;
    }
  }
}

// Icon-only rail: hides link titles, centers icons and turns the inline submenus
// flattened by navbar-vertical-nav() back into floating flyout dropdowns.
@mixin navbar-vertical-folded {
  // Flyouts must escape the rail, so the folded sidebar itself cannot scroll.
  overflow: visible;

  // A wide brand (e.g. a full logo) must not push the container beyond the
  // rail width; the brand crops instead.
  [class^='container'] {
    min-width: 0;
  }

  // The brand keeps the expanded state's start padding, so the logo does not
  // move when the sidebar folds; anything wider than the rail crops.
  .navbar-brand {
    overflow: hidden;
  }

  // The pin button lives on the expanded sidebar only; the folded rail
  // unfolds by hovering (folded-hover) or via an outside control.
  [data-bs-toggle='sidebar-folded'] {
    display: none;
  }

  // The list inset and link padding are identical in both states, so the
  // icons keep their exact position — only the titles collapse. Aside-wide
  // (not .navbar-collapse-scoped), so the footer outside the collapse folds
  // the same way.
  .navbar-nav .nav-link {
    --nav-link-icon-margin-end: 0;
  }

  // Only icons are readable in the rail, so the group holding the current page
  // takes the pill back — the emphasis the expanded sidebar carries on the
  // title alone cannot be seen here. Scoped through .navbar-nav to match the
  // specificity of the rule it overrides, which wins on source order.
  // stylelint-disable-next-line selector-max-class
  .navbar-nav .nav-item.active > .nav-link.dropdown-toggle {
    background: var(--navbar-active-bg);
  }

  // Collapsed, not display: none — titles stay in the accessibility tree.
  .nav-link-title {
    width: 0;
    overflow: hidden;
    white-space: nowrap;
    opacity: 0;
  }

  .navbar-collapse {
    // Flyouts must escape the nav's scroll area; the folded rail therefore
    // cannot scroll (documented — the hover variant is the escape hatch).
    overflow: visible;

    // The label text cannot fit the rail — indent it away (stays in the
    // accessibility tree, line box keeps the element height stable) and show
    // a short separator instead, centered within the WHOLE gap between the
    // groups: the box's 50% is shifted up by half the label's top margin.
    .nav-section-title {
      position: relative;
      overflow: hidden;
      text-indent: -9999px;
      white-space: nowrap;

      &::before {
        position: absolute;
        inset-inline-start: calc(50% - 0.625rem);
        top: calc(50% - var(--sidebar-section-title-margin-top) / 2);
        width: 1.25rem;
        height: var(--border-width);
        content: '';
        background: #{color-transparent(var(--navbar-color), 0.2)};
      }

      // Nothing above the first group to separate — no line, and no margin
      // shift to compensate for either.
      &:first-child::before {
        content: none;
      }
    }

    .nav-link.dropdown-toggle::after {
      display: none;
    }

    // Restore the multi-column layout that navbar-vertical-nav() stacks —
    // it keeps long flyout menus from overflowing the viewport.
    .dropdown-menu-columns {
      flex-direction: row;
    }

    .dropdown-menu {
      position: absolute;
      inset-inline-start: 100%;
      top: 0;
      min-width: var(--dropdown-min-width);
      padding: var(--dropdown-padding-y) var(--dropdown-padding-x);
      margin: 0;
      color: var(--dropdown-color);
      background-color: var(--dropdown-bg);
      background-clip: padding-box;
      // No border — like the base .dropdown-menu, whose edge is the 1px ring
      // built into --shadow-dropdown.
      box-shadow: var(--dropdown-box-shadow);
      @include border-radius(var(--dropdown-border-radius));

      .dropdown-item {
        padding: var(--dropdown-item-padding-y) var(--dropdown-item-padding-x);
        color: var(--dropdown-link-color);
        @include border-radius(0);
      }

      // Undo the tree indents navbar-vertical-nav() puts on nested levels.
      .dropdown-menu .dropdown-item {
        padding-inline-start: var(--dropdown-item-padding-x);
      }

      // stylelint-disable-next-line selector-max-class, selector-max-compound-selectors
      .dropdown-menu .dropdown-menu .dropdown-item {
        padding-inline-start: var(--dropdown-item-padding-x);
      }
    }

    // The nav list is inset, so 100% of the .dropdown lands short of the rail
    // edge — compensate for the inset and add a small gap, so the flyout's
    // border does not sit flush against the rail's edge border. Nested
    // (dropend) flyouts are not inset and keep the plain 100%.
    .nav-item > .dropdown-menu {
      inset-inline-start: calc(100% + var(--sidebar-inset) + 0.25rem);
    }
  }
}

/**
Navbar
 */
.navbar {
  --navbar-bg: var(--bg-surface);
  --navbar-border-width: #{$navbar-border-width};
  --navbar-active-border-color: #{$navbar-active-border-color};
  --navbar-active-bg: #{$navbar-light-active-bg};
  --navbar-border-color: #{$navbar-border-color};
  --navbar-hover-color: #{$navbar-hover-color};
  align-items: stretch;
  min-height: $navbar-height;
  color: var(--navbar-color);
  background: var(--navbar-bg);
  box-shadow: inset 0 calc(-1 * var(--navbar-border-width)) 0 0 var(--navbar-border-color);

  @include media-print() {
    display: none;
  }

  .navbar-collapse & {
    flex-grow: 1;
  }

  &.collapsing {
    min-height: 0;
  }

  .dropdown-menu {
    position: absolute;
    z-index: $zindex-fixed;
  }

  .navbar-nav {
    --nav-link-icon-margin-end: #{$nav-link-icon-margin-end};
    min-height: subtract($navbar-height, 2 * $navbar-padding-y);

    // Section labels only make sense in a vertical list — the vertical
    // navbar styles re-enable them.
    .nav-section-title {
      display: none;
    }

    .nav-link {
      position: relative;
      justify-content: center;
      min-width: 2.5rem;
      min-height: 2.5rem;
      @include border-radius(var(--border-radius));

      .badge {
        position: absolute;
        inset-inline-end: 0.5rem;
        top: 0.5rem;

        /* rtl:ignore */
        transform: translate(calc(var(--dir) * 50%), -50%);
      }
    }
  }
}

.navbar-expand {
  @each $breakpoint in map.keys($grid-breakpoints) {
    $next: breakpoint-next($breakpoint, $grid-breakpoints);
    $infix: breakpoint-infix($next, $grid-breakpoints);

    &#{$infix} {
      @include media-breakpoint-down(breakpoint-next($breakpoint)) {
        @include navbar-vertical-nav();

        // Below the breakpoint the vertical navbar is a top bar row: toggler,
        // brand, and whatever trails them (a user block, or nothing). Auto
        // margins keep the brand centered either way — space-between alone
        // would push it to the far edge when nothing follows it.
        &.navbar-vertical .navbar-brand {
          margin-inline: auto;
        }

        // In the stacked mobile menu nothing pins the trailing group to the
        // bottom, so a small gap marks it as a separate part of the menu.
        &.navbar-vertical .navbar-side {
          margin-top: $sidebar-inset;
        }

        // Below the breakpoint the navbar-footer sits in the top bar row:
        // the avatar alone, with its menu dropping down instead of up.
        .navbar-footer {
          .nav-link-title {
            display: none;
          }

          .dropup .dropdown-menu {
            inset-inline-start: auto;
            inset-inline-end: 0;
            top: 100%;
            bottom: auto;
          }
        }
      }

      @include media-breakpoint-up($next) {
        .navbar-collapse {
          flex: 1 1 auto;
          width: auto;
        }

        .nav-item.active {
          position: relative;

          .nav-link {
            color: var(--navbar-active-color);
          }

          &::after {
            position: absolute;
            inset-inline-start: 0;
            inset-inline-end: 0;
            bottom: -0.25rem;
            content: '';
            border: 0 var(--border-style) var(--navbar-active-border-color);
            border-bottom-width: 2px;
          }
        }

        &.navbar-vertical {
          box-shadow: inset calc(-1 * var(--navbar-border-width)) 0 0 0 var(--navbar-border-color);

          &.navbar-right,
          &.navbar-end {
            box-shadow: inset calc(1 * var(--navbar-border-width)) 0 0 0 var(--navbar-border-color);
          }
        }

        &.navbar-vertical {
          ~ .navbar,
          ~ .page-wrapper {
            margin-inline-start: var(--sidebar-width);
          }
        }

        &.navbar-vertical.navbar-right,
        &.navbar-vertical.navbar-end {
          ~ .navbar,
          ~ .page-wrapper {
            margin-inline-start: 0;
            margin-inline-end: var(--sidebar-width);
          }
        }
      }

      // In the first, tightest segment after a horizontal navbar expands there
      // is no room for icons — hide them there, derived from the navbar's own
      // navbar-expand-* breakpoint, so the markup needs no display utilities.
      // The vertical navbar always shows its icons.
      @if $next and breakpoint-next($next, $grid-breakpoints) {
        @include media-breakpoint-only($next) {
          &:not(.navbar-vertical) .navbar-nav .nav-link-icon {
            display: none;
          }
        }
      }
    }
  }
}

/**
Navbar brand
 */
.navbar-brand {
  display: inline-flex;
  gap: $spacer-2;
  align-items: center;
  margin: 0;
  font-weight: $navbar-brand-font-weight;
  line-height: 1;
}

.navbar-brand-image {
  width: auto;
  height: $navbar-brand-image-height;
}

.navbar-brand-gray {
  --navbar-logo-color: var(--tertiary);
  opacity: 0.5;
}

/**
Navbar toggler
 */
.navbar-toggler {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: $navbar-brand-image-height;
  height: $navbar-brand-image-height;
  border: 0;
}

.navbar-toggler-icon {
  position: relative;
  // The button's padding leaves less room than the bar is wide — without
  // this the middle bar gets flex-squeezed while the pseudo bars keep their
  // inherited width, and the open-state X loses a leg.
  flex-shrink: 0;
  width: 1.25em;
  height: 2px;
  background: currentColor;
  @include border-radius(var(--border-radius-pill));
  @include transition(top $navbar-toggler-animation-time $navbar-toggler-animation-time, bottom $navbar-toggler-animation-time $navbar-toggler-animation-time, transform $navbar-toggler-animation-time, opacity 0s $navbar-toggler-animation-time);

  &::before,
  &::after {
    position: absolute;
    inset-inline-start: 0;
    display: block;
    width: inherit;
    height: inherit;
    content: '';
    background: inherit;
    border-radius: inherit;
    @include transition(inherit);
  }

  &::before {
    top: -0.45em;
  }

  &::after {
    bottom: -0.45em;
  }

  .navbar-toggler[aria-expanded='true'] & {
    transform: rotate(45deg);
    @include transition(top $transition-time, bottom $transition-time, transform $transition-time $transition-time, opacity 0s $transition-time);

    &::before {
      top: 0;
      transform: rotate(-90deg);
    }

    &::after {
      bottom: 0;
      opacity: 0;
    }
  }
}

/**
Navbar transparent
 */
.navbar-transparent {
  --navbar-border-color: transparent !important;
  background: transparent !important;
}

/**
Navbar nav
 */
.navbar-nav {
  --nav-link-hover-bg: #{$navbar-nav-link-hover-bg};
  --nav-link-icon-color: #{$nav-link-icon-color};
  --nav-link-hover-icon-color: #{$nav-link-hover-icon-color};
  align-items: stretch;
  padding: 0;
  margin: 0;

  .nav-item {
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}

/**
Navbar side
 */
// The group at the end of a navbar: a row on the end side of a horizontal
// navbar. In a vertical navbar the same class pins the group to the bottom
// of the menu — see navbar-vertical-nav().
.navbar-side {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-around;
  margin: 0;
}

/**
Navbar sticky
 */
// Runtime route only (data-bs-navbar="sticky" on <html>); static markup wraps
// the navbar in its own .sticky-top. Just the top bar sticks — on the two-row
// navbar the menu row scrolls away, so the sticky strip stays one row high.
html[data-bs-navbar='sticky'] .page > .navbar:not(.navbar-vertical) {
  position: sticky;
  top: 0;
  z-index: $zindex-sticky;
}

/**
Navbar primary
 */
// Runtime route only (data-bs-navbar-theme="primary" on <html>): the primary
// color as the navbar surface. The text palette comes from the dark color
// mode, which _extends.scss applies to the same selector; static markup gets
// the same look from .bg-primary with data-bs-theme="dark" on the navbar.
html[data-bs-navbar-theme='primary'] .page > .navbar {
  --navbar-bg: var(--primary);
  --navbar-border-color: transparent;
}

/**
Navbar vertical
 */
@if $enable-navbar-vertical {
  // Folded sidebar: every geometry consumer (aside width, page paddings,
  // page-wrapper/navbar margins) reads --sidebar-width, so flipping this one
  // variable re-lays-out the whole page. Two routes to the same state:
  // a .navbar-folded/.navbar-folded-hover class on the aside (static markup),
  // or data-bs-sidebar="folded"/"folded-hover" on <html> (set pre-render from
  // localStorage by tabler-theme.js, toggled by [data-bs-toggle="sidebar-folded"]).
  // html[…] beats the :root declaration of --sidebar-width on the same element;
  // a bare :where()/[…] selector would lose to it and never take effect.
  html[data-bs-sidebar^='folded'] {
    --sidebar-width: var(--sidebar-folded-width);

    // The sidebar is rendered for the expanded state, so the active submenu can
    // arrive open (.show). Folded, it would paint as a flyout until sidebar.ts
    // closes it on DOMContentLoaded — a flicker on every reload. Menus opened by
    // the Dropdown plugin carry a popper data attribute (data-tblr-popper from
    // tabler.js, data-bs-popper from Bootstrap's own js), so only the
    // server-rendered ones hide.
    .navbar-vertical .dropdown-menu.show:not([data-bs-popper]):not([data-tblr-popper]) {
      display: none;
    }
  }

  .navbar-vertical:is(.navbar-folded, .navbar-folded-hover) {
    --sidebar-width: var(--sidebar-folded-width);

    // The class sits on the aside, so its layout siblings need their own copy.
    ~ .page,
    ~ .page-wrapper,
    ~ .navbar {
      --sidebar-width: var(--sidebar-folded-width);
    }
  }

  // Navbar position (data-bs-navbar-position on <html>). A page can render both
  // navbars — the vertical aside first, the horizontal navbar(s) after — and
  // these rules show one of them. Horizontal is the default and writes no
  // attribute, so its rule matches on the attribute's absence.
  //
  // Both rules are guarded with :has() so they only fire on a page that really
  // renders the other navbar: a page with a single navbar keeps it, whatever a
  // stale stored choice says, and can never end up with no navigation at all.
  html:not([data-bs-navbar-position='vertical']) .page:has(> [class*='navbar-expand']:not(.navbar-vertical)) {
    > .navbar-vertical {
      display: none;
    }

    // The hidden aside must leave no gap: its siblings offset themselves by
    // --sidebar-width, and this declaration sits on the same elements as the
    // folded copy above, so it wins by coming later.
    > .navbar,
    > .page-wrapper {
      --sidebar-width: 0;
    }
  }

  html[data-bs-navbar-position='vertical'] .page:has(> .navbar-vertical) {
    > [class*='navbar-expand']:not(.navbar-vertical) {
      display: none;
    }
  }

  .navbar-vertical {
    &.navbar-expand {
      @each $breakpoint in map.keys($grid-breakpoints) {
        $next: breakpoint-next($breakpoint, $grid-breakpoints);
        $infix: breakpoint-infix($next, $grid-breakpoints);

        &#{$infix} {
          @include media-breakpoint-up($next) {
            position: fixed;
            inset-inline-start: 0;
            top: 0;
            bottom: 0;
            z-index: $zindex-fixed;
            align-items: start;
            width: var(--sidebar-width);
            padding: 0;
            @include transition(transform $transition-time);

            &.navbar-right,
            &.navbar-end {
              inset-inline-start: auto;
              inset-inline-end: 0;
            }

            // Logo on the start side, room for an action (e.g. the pin
            // toggle) on the end side. The inline padding centers the logo
            // mark in the folded rail and is identical in both states, so the
            // logo mark and the nav icons share one center axis and nothing
            // moves when the sidebar folds.
            .navbar-brand {
              --sidebar-brand-padding-x: #{$sidebar-brand-padding-x};
              justify-content: space-between;
              padding: (($navbar-height - $navbar-brand-image-height) * 0.5) var(--sidebar-brand-padding-x);
              margin-inline-end: 0;
            }

            // The fold toggle keeps its layout slot (no jumping) but only
            // becomes visible while the sidebar is hovered or focused.
            [data-bs-toggle='sidebar-folded'] {
              opacity: 0;
              @include transition(opacity $transition-time);
            }

            &:hover [data-bs-toggle='sidebar-folded'],
            &:has(:focus-visible) [data-bs-toggle='sidebar-folded'] {
              opacity: 1;
            }

            // The nav is the sidebar's scroll area — the brand above and the
            // footer below stay pinned.
            .navbar-collapse {
              align-items: stretch;
              min-height: 0;
              overflow-y: auto;
            }

            .navbar-nav {
              flex-grow: 1;
              flex-direction: column;
              min-height: auto;

              .nav-link {
                padding-top: 0.5rem;
                padding-bottom: 0.5rem;
              }
            }

            // Bottom-pinned footer area, e.g. a user block. Sits after the
            // growing nav, separated with the navbar border.
            .navbar-footer {
              // In the markup the footer sits before the collapse (so it
              // stays in the mobile top bar row); order moves it to the
              // bottom of the desktop column.
              order: 1;
              padding-block: $sidebar-inset;
              margin-top: auto;
              border-top: var(--navbar-border-width) var(--border-style) var(--navbar-border-color);

              // Tighter link padding than the menu — the avatar brings its
              // own bulk. Overrides the variables the nav-link padding reads,
              // so it wins regardless of rule order.
              .navbar-nav {
                --sidebar-nav-padding-y: 0.5rem;
                --sidebar-nav-padding-x: 0.5rem;
                flex-grow: 0;
              }

              .nav-link .avatar {
                // Never squeezed by the appearing title during the hover
                // unfold animation.
                flex-shrink: 0;
                margin-inline-end: var(--nav-link-icon-margin-end);
              }
            }

            > [class^='container'] {
              flex-direction: column;
              align-items: stretch;
              justify-content: start;
              height: 100%;
              padding: 0;
            }

            ~ .page {
              padding-inline-start: var(--sidebar-width);

              [class^='container'] {
                padding-inline-start: 1.5rem;
                padding-inline-end: 1.5rem;
              }
            }

            &.navbar-right ~ .page,
            &.navbar-end ~ .page {
              padding-inline-start: 0;
              padding-inline-end: var(--sidebar-width);
            }

            @include navbar-vertical-nav();

            // Folded state, both routes; the hover variant folds only while
            // not hovered and not holding visible keyboard focus. Plain
            // :focus-within would keep the sidebar stuck open after a mouse
            // click, because the clicked link keeps focus.
            &:is(.navbar-folded, .navbar-folded-hover:not(:hover):not(:has(:focus-visible))),
            :where([data-bs-sidebar='folded']) &,
            :where([data-bs-sidebar='folded-hover']) &:not(:hover):not(:has(:focus-visible)) {
              @include navbar-vertical-folded();
            }

            &.navbar-folded-hover,
            :where([data-bs-sidebar='folded-hover']) & {
              @include transition(transform $transition-time, width $transition-time);

              .nav-link-title {
                @include transition(opacity $transition-time);
              }

              // Temporarily unfolds as an overlay: siblings keep the folded
              // --sidebar-width, so page content does not reflow.
              &:hover,
              &:has(:focus-visible) {
                width: $sidebar-width;
                box-shadow:
                  inset calc(-1 * var(--navbar-border-width)) 0 0 0 var(--navbar-border-color),
                  var(--shadow-lg);
              }
            }
          }
        }
      }
    }
  }

  @include media-print() {
    .navbar-vertical ~ .page {
      padding-inline-start: 0;
      padding-inline-end: 0;
    }
  }
}

.navbar-overlap {
  &::after {
    position: absolute;
    inset-inline-start: 0;
    inset-inline-end: 0;
    top: 100%;
    z-index: -1;
    height: $navbar-overlap-height;
    content: '';
    background: inherit;
    box-shadow: inherit;
  }
}
