/* ==========================================================================
   App shell, sidebar drawer, backdrop, fh-preload first-paint guard.
   Owning feature: app chrome
   Load order is defined in Views/Shared/_CssIncludes.cshtml — do not reorder.
   ========================================================================== */

/* --- Shell -------------------------------------------------------------- */
body { background-color: var(--fh-bg); }

/* ==========================================================================
   App shell + sidebar drawer
   --------------------------------------------------------------------------
   Owns the whole page frame: a fixed navbar, a left nav drawer, and the
   content well. Self-contained vanilla CSS — no framework layout classes are
   involved, so nothing here can be re-styled out from under us by a vendor
   stylesheet.

   The left nav is CLOSED at every width until the user opens it — that is the
   stylesheet's resting state, so the first paint is correct before any script
   runs and a full page load always starts hidden. `body.fh-drawer-open` is
   the single switch, and it has two meanings, split at 992px:

     < 992px  OVERLAY. It floats OVER the content — nothing in flow moves —
              with a dismissing backdrop, and the page behind it is
              scroll-locked and inert. The phone and tablet ranges are
              deliberately not split: a 280px column cannot be carved out of a
              360px screen, and at 768px it would leave 488px, narrower than
              the Browse grid's two-column minimum plus its detail panel. One
              behaviour, one set of rules, up to 992px.
     >=992px  PUSH. The sidebar slides in beside the content and .fh-main /
              .fh-footer yield its width via margin-left, so the content
              slides right rather than being covered. Non-modal: no backdrop,
              no scroll lock, no focus trap, because nothing is obscured and
              the rest of the page stays usable with the sidebar open.

   `body.fh-drawer-open` means "open" in BOTH modes — the hamburger is a live
   toggle at every width and is the only way in or out. What changes across
   the line is what open *does*: cover, or displace.

   The 992px line is repeated in site.js (matchMedia). Both must agree.

   The document itself is the scroller (no `overflow` on .fh-main): the navbar
   is taken out of flow and .fh-app reserves its height with padding-top
   instead. That is what lets `position: sticky` work for .fh-content-head,
   which resolves against the viewport scrollport. Permissions and Admin
   Files size their own shells to the leftover viewport and scroll inside
   each pane instead. Push mode does not disturb this: .fh-main is offset by
   margin, which creates neither a scrollport nor a containing block.

   Z-index ladder, low to high — every layer that can overlap another is named
   here once so the order is checkable in one place:
     1020  .fh-content-head        sticky breadcrumb/toolbar band
     1022  .fh-upload-fab          floating upload button
     1025  .fh-selection-toolbar   floating selection bar
     1030  --fh-z-backdrop         drawer backdrop
     1035  .fh-permissions-picker-list
     1040  --fh-z-sidebar          the drawer itself, over the backdrop
     1050  --fh-z-navbar           over the drawer, so the hamburger stays
                                   clickable while the drawer is open
     1055  (Bootstrap modals/offcanvas; also .fh-drag-overlay — deliberately
            left above the chrome)
     1060  .fh-dropdown, .fh-upload-dock
                                   menus/dock, which must clear even a
                                   modal-adjacent bar — including the sticky
                                   .fh-content-head. That only works if no
                                   ancestor between the menu and the root
                                   creates a stacking context below 1060
                                   (.fh-card and .fh-card-menu must not set
                                   z-index; the ⋮ toggle may).
     1080  .fh-toast-host          toasts
     1090  .fh-nav-progress        page-level loading sweep

   The upload FAB and selection toolbar sit below the backdrop (1022/1025 <
   1030) so a modal drawer actually covers them, per the drawer's own modal
   contract above. The upload dock and toast host are the deliberate
   exception: both are bottom-right, transient status surfaces that never
   overlap the hamburger, so there is no reason to duck them under the drawer
   the way the FAB and selection toolbar must be.
   ========================================================================== */
:root {
  --fh-sidebar-w: 13.5rem;
  --fh-z-backdrop: 1030;
  --fh-z-sidebar: 1040;
  --fh-z-navbar: 1050;
}

@media (min-width: 992px) {
  :root { --fh-sidebar-w: 16rem; }
}
@media (min-width: 1440px) and (max-width: 1919.98px) {
  :root { --fh-sidebar-w: 18rem; }
}
@media (min-width: 1920px) and (max-width: 2559.98px) {
  :root { --fh-sidebar-w: 20rem; }
}
@media (min-width: 2560px) and (max-width: 3839.98px) {
  :root { --fh-sidebar-w: 22rem; }
}
@media (min-width: 3840px) {
  :root { --fh-sidebar-w: 24rem; }
}

.fh-app {
  /* The navbar is fixed, so the shell reserves its height here rather than
     each page compensating for it. */
  padding-top: var(--fh-header-h);
}

.fh-navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--fh-header-h);
  z-index: var(--fh-z-navbar);
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0 1.25rem;
}

.fh-main {
  /* Containing block for the marquee band (browse.js), which must scroll with
     the grid. Inert for the sticky/fixed descendants — only transform or
     filter would capture those.
     The document is the scroller (see the shell header comment): `.fh-main`
     only fills short pages up to the leftover viewport via `min-height` — no
     `max-height` and no `overflow`, or tall content (long search results,
     deep Browse trees) would be clipped with no way to reach it. */
  position: relative;
  min-height: calc(100vh - 7.5rem);
}

/* --- Sidebar drawer (base = mobile and tablet) ---------------------------
   `position: fixed` and parked off-canvas, brought back by translating it.
   Because it never participates in flow, opening it cannot reflow anything:
   the content stays exactly where it was and the drawer floats over it. The
   same `fixed` element is reused for the desktop column below, which is what
   lets it keep an independent scroll region there no matter how tall the page
   gets. It starts at --fh-header-h rather than the top of the viewport so it
   can never cover the hamburger that dismisses it — the other half of that
   guarantee is the navbar outranking it in the z-index ladder above. */
.fh-sidebar {
  position: fixed;
  top: var(--fh-header-h);
  bottom: 0;
  left: 0;
  width: var(--fh-sidebar-w);
  z-index: var(--fh-z-sidebar);
  background-color: var(--fh-sidebar);
  display: flex;
  flex-direction: column;
  transform: translateX(-100%);
  transition: transform 200ms ease;
  border-right: 1px solid var(--fh-border);
}

body.fh-drawer-open .fh-sidebar {
  transform: none;
}

/* Starts below the navbar for the same reason the drawer does: it must never
   cover the hamburger that dismisses it. */
.fh-backdrop {
  position: fixed;
  inset: var(--fh-header-h) 0 0 0;
  z-index: var(--fh-z-backdrop);
  background: rgba(15, 23, 42, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease;
}

body.fh-drawer-open .fh-backdrop {
  opacity: 1;
  pointer-events: auto;
}

.fh-sidebar-brand {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  min-height: var(--fh-header-h);
  padding: 0 1rem;
  border-bottom: 1px solid var(--fh-border);
}
.fh-sidebar-brand a {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  min-width: 0;
  color: var(--fh-text);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-tighter);
  text-decoration: none;
}
.fh-sidebar-brand .fh-brand-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The only scroll region inside the drawer, so a long menu scrolls while the
   brand block stays put. */
.fh-sidebar-body {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.fh-main,
.fh-footer {
  margin-left: 0;
}

@media (min-width: 992px) {
  .fh-navbar {
    left: var(--fh-sidebar-w);
  }

  .fh-sidebar {
    top: 0;
    transform: none;
    transition: none;
  }

  body.fh-drawer-open .fh-sidebar {
    transform: none;
  }

  .fh-main,
  .fh-footer {
    margin-left: var(--fh-sidebar-w);
    transition: margin-left 200ms ease;
  }

  /* Sidebar is a pinned column at every desktop width (992px through 4K).
     No drawer to open, so the hamburger and its backdrop must not display.
     min-width: 992px has no upper bound — 1024, 1440, 1920, 2560, 3840+
     all match. A later `.fh-burger { display: inline-flex }` must not
     override this; that display is gated to ≤991.98px below. */
  .fh-burger,
  .fh-backdrop {
    display: none;
  }
}

@media (max-width: 991.98px) {
  .fh-main,
  .fh-footer {
    transition: margin-left 200ms ease;
  }
}

/* Everything `fh-drawer-open` animates: the sidebar's slide, the backdrop's
   fade, and the content's push. */
@media (prefers-reduced-motion: reduce) {
  .fh-sidebar,
  .fh-backdrop,
  .fh-main,
  .fh-footer { transition: none; }
}

/* Anti-flash guard for a warm navigation that restores an open drawer (see
   the inline script at the top of <body> in _Layout.cshtml, and site.js's
   sessionStorage persistence). `fh-preload` is on <body> for exactly the
   first frame, so if the browser finds anything to transition between while
   `fh-drawer-open` is already applied at parse time, it snaps into place
   instead of visibly sliding/fading in. site.js removes the class right
   after DOMContentLoaded, after which normal transitions resume. */
body.fh-preload .fh-sidebar,
body.fh-preload .fh-backdrop,
body.fh-preload .fh-main,
body.fh-preload .fh-footer {
  transition: none !important;
}

