/* ==========================================================================
   Typography — Google Sans Flex (Google Fonts) with system fallback.
   Loaded via shared layout (`<link rel="stylesheet">`) so only the four weights
   below are fetched, with `display=swap` to avoid invisible text.
   ========================================================================== */
:root {
  --fh-font-sans: "Google Sans Flex", "Google Sans", system-ui, -apple-system,
                  "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans",
                  "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
}

/* Modular type scale — the ONLY font-size/weight/leading/tracking values the
   app may use. Components used to hard-code ~40 ad-hoc sizes (0.82rem, 0.86rem,
   0.775rem, 10px, …), so two equal-level labels on different pages could differ
   by a px and there was no shared answer to "how big is a page title?". This
   block replaces that with one step-based rem scale.

   Sizes are pure rem, so every step inherits the root clamp's 360px→768px ramp
   and the ≥2560px bump automatically (a px-based floor would break that). The
   px notes are at the 16px reference root; on a 360px phone the whole scale
   sits at 87.5% of those numbers, which is the intended behaviour — one
   proportional shrink, not a per-component pixel fight. The smallest *text*
   step (xs) is the ~12px accessibility floor at the reference root; 2xs exists
   for decorative glyphs only and must never carry prose.

   Naming: --fh-text (no suffix) is the ink COLOUR token; every --fh-text-* with
   a step suffix is a SIZE token. Reading `font-size: var(--fh-text-sm)` against
   `color: var(--fh-text)` reads as "13px" vs "ink" respectively.

   Roles
   -----
   --fh-text-2xs 0.6875rem (11px)  carets, chevrons, dots, sort arrows — glyphs
                                   only, never words.
   --fh-text-xs   0.75rem (12px)   micro labels: uppercase column headers,
                                   badges, timestamps, kbd, hint bars.
   --fh-text-sm   0.8125rem (13px) secondary/meta text, dense table & list body.
   --fh-text-base 0.875rem (14px)  app body default: controls, buttons, nav,
                                   cards, menus, modal/dropdown body text.
   --fh-text-md   0.9375rem (15px) emphasized body: the "+ New" primary CTA,
                                   auth inputs and buttons.
   --fh-text-lg   1rem (16px)      modal titles, item/card names, section names.
   --fh-text-xl   1.125rem (18px)  empty-state titles, brand, preview h3.
   --fh-text-2xl  1.25rem (20px)   small headings (preview h2, stat values).
   --fh-text-3xl  1.5rem (24px)    page titles (.fh-page-title), preview h1.
   --fh-text-4xl  1.75rem (28px)   Home/login titles, hero quota/stat numbers.
   --fh-text-5xl  2.25rem (36px)   display glyphs (empty-state icons).
   --fh-text-6xl  3rem (48px)      hero glyphs (drag overlay, empty trash,
                                   details-panel thumb, preview icon). */
:root {
  --fh-text-2xs: 0.6875rem;
  --fh-text-xs: 0.75rem;
  --fh-text-sm: 0.8125rem;
  --fh-text-base: 0.875rem;
  --fh-text-md: 0.9375rem;
  --fh-text-lg: 1rem;
  --fh-text-xl: 1.125rem;
  --fh-text-2xl: 1.25rem;
  --fh-text-3xl: 1.5rem;
  --fh-text-4xl: 1.75rem;
  --fh-text-5xl: 2.25rem;
  --fh-text-6xl: 3rem;

  /* Weight roles — 400 body, 500 labels/buttons/chips/active row, 600 headings
     + selected/active chrome + column headers + item names, 700 page titles
     and hero numbers. Equal-level text must render at the same weight, so if a
     new control "feels" like an existing one it should reuse that control's
     weight rather than inventing a new one. */
  --fh-weight-regular: 400;
  --fh-weight-medium: 500;
  --fh-weight-semibold: 600;
  --fh-weight-bold: 700;

  /* Line-height roles — none for glyph-only rows, tight for titles (so
     multi-line Vietnamese card names keep their vertical rhythm without
     colliding), snug for compact meta/secondary text, normal for body copy. */
  --fh-leading-none: 1;
  --fh-leading-tight: 1.25;
  --fh-leading-snug: 1.35;
  --fh-leading-normal: 1.5;

  /* Letter-spacing roles — tight for headings, tighter for display sizes
     (≥3xl), normal for body (default, rarely written), wide for uppercase
     micro-labels and small tracked headings. The old code drifted across
     eleven values (-0.04em … 0.1em); these four cover every case. */
  --fh-tracking-tight: -0.01em;
  --fh-tracking-tighter: -0.02em;
  --fh-tracking-normal: 0;
  --fh-tracking-wide: 0.05em;
}

/* Root font size drives every rem in the app. It used to step 14px → 16px at a
   hard `min-width: 768px` boundary, so 767px and 768px rendered the whole UI at
   a 14% different scale — a visible reflow jump landing exactly on the
   768x1024 tablet target. A clamp() ramp interpolates the same 14px → 16px
   across the phone→tablet range instead, then holds 16px, and only steps up
   again on genuinely large displays (see the wide-screen block below) so a 4K
   TV viewed from across a room isn't rendering 16px body text. */
html {
  font-family: var(--fh-font-sans);
  /* 0.875rem (14px) at 360px wide → 1rem (16px) at 768px, then held.
     Expressed in rem, not px, so a reader who has raised their browser's
     default font size still gets it honoured (a px root size silently
     overrides that preference). */
  font-size: clamp(0.875rem, 0.7647rem + 0.4902vw, 1rem);
  font-feature-settings: "cv11", "ss01", "ss03";
}

/* ≥2560px: nudge the base scale up rather than letting the UI shrink into the
   middle of a very large panel. 1rem at 2560 → 1.125rem (18px) at 3840; capped
   there, since beyond that line lengths and control sizes stop reading as an
   app and start reading as a slide deck. */
@media (min-width: 2560px) {
  html {
    font-size: clamp(1rem, 0.75rem + 0.1563vw, 1.125rem);
  }
}

body {
  font-family: var(--fh-font-sans);
  font-optical-sizing: auto;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: var(--fh-font-sans);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-tight);
  color: var(--fh-text);
}
/* Bootstrap's own heading ladder (2.5rem…1rem) is off the app's scale, so it
   gets mapped onto the type tokens — page titles, preview, modals and any
   plain Bootstrap heading then all speak the same size language. */
h1, .h1 { font-size: var(--fh-text-3xl); }
h2, .h2 { font-size: var(--fh-text-2xl); }
h3, .h3 { font-size: var(--fh-text-xl); }
h4, .h4 { font-size: var(--fh-text-lg); }
h5, .h5 { font-size: var(--fh-text-md); }
h6, .h6 { font-size: var(--fh-text-base); }

/* Bootstrap CSS variables — overrides apply to Bootstrap modals, dropdowns,
   tables, forms, and every component that reads `--bs-body-font-*`. */
:root {
  --bs-font-sans-serif: var(--fh-font-sans);
  --bs-body-font-family: var(--fh-font-sans);
  /* Bootstrap's Reboot defaulted unclassed text to 1rem/400/#212529 — a
     second, inconsistent typography beside the app's 0.875rem body. Point the
     whole Bootstrap layer at the same tokens so tables, modals, dropdowns,
     forms, toasts and badges inherit the app's sizes, weights and inks. */
  --bs-body-font-size: var(--fh-text-base);
  --bs-body-font-weight: var(--fh-weight-regular);
  --bs-body-line-height: var(--fh-leading-normal);
  --bs-body-color: var(--fh-text);
  --bs-secondary-color: var(--fh-muted);
  --bs-heading-color: var(--fh-text);
}

/* Keyboard-only focus ring. Was on `:focus`, which fired on every mouse click
   too and painted a ring over buttons the user had merely pressed; and its
   inner `white` halo was a literal, so on the dark sidebar it drew a white
   band. `:focus-visible` restricts it to keyboard/AT focus, and the halo now
   reads from the surface token so it works on light and dark chrome alike. */
.btn:focus-visible, .btn-link.nav-link:focus-visible,
.form-control:focus-visible, .form-check-input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 0.1rem var(--fh-focus-halo, #fff), 0 0 0 0.25rem #258cfb;
}
.fh-sidebar {
  --fh-focus-halo: #fff;
}

/* Page-level overflow guard. Individual surfaces are responsible for scrolling
   their own wide content (tables live in .table-responsive, the breadcrumb in
   its own scroller); this makes sure that when one of them regresses the page
   itself still can't grow a horizontal scrollbar and shear the fixed navbar
   and sidebar away from the content. `overflow-x: clip` rather than `hidden`
   so it doesn't turn <body> into a scroll container — `hidden` would break
   `position: sticky` on .fh-content-head.

   Deliberately on `html` only, not also on `body`: overflow set on the root
   element propagates to the viewport, and sticky positioning is resolved
   against that same viewport scrollport, so the guard and .fh-content-head's
   `position: sticky` don't interact. A clip container on `body` would sit
   *between* the sticky element and the viewport, which is the arrangement
   that breaks it. */
html {
  position: relative;
  min-height: 100%;
  overflow-x: clip;
}

body {
  /* The old `margin-bottom: 60px` paired with the default template's
     `.footer { position: absolute; bottom: 0 }` — markup this app no longer
     renders (.fh-footer is in normal flow). All it did was leave 60px of dead
     grey below the footer on every page at every width. */
  max-width: 100%;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--bs-secondary-color);
  text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
  text-align: start;
}

/* Folder tree (Browse sidebar + move/copy picker modals) — Windows-Explorer-style
   nesting: each depth level gets its own indent plus a guide line so parent/child
   relationships stay visible at a glance, however deep the tree goes. */
.tree-children {
  margin-left: 0.55rem;
  padding-left: 0.85rem;
  border-left: 1px solid #dee2e6;
}

.tree-row:hover {
  background-color: var(--fh-primary-soft, #eff6ff);
}

.tree-link {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- Modern Destination Folder Tree Picker (.fh-tree-picker) -------------- */
.fh-tree-picker {
  border: 1px solid var(--fh-border, #e2e8f0);
  border-radius: 0.5rem;
  background-color: #fff;
  padding: 0.5rem;
  min-height: 180px;
  user-select: none;
}
/* Move/Copy modal variant — bounded height with its own scroll region so the
   modal body doesn't grow past the viewport on a deep tree. */
.fh-tree-picker-scroll {
  max-height: 50vh;
  overflow-y: auto;
}

.fh-tree-picker::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
.fh-tree-picker::-webkit-scrollbar-thumb {
  background-color: #cbd5e1;
  border-radius: 3px;
}
.fh-tree-picker::-webkit-scrollbar-thumb:hover {
  background-color: var(--fh-muted);
}
.fh-tree-picker::-webkit-scrollbar-track {
  background: transparent;
}

.picker-tree-item {
  list-style: none;
  margin-bottom: 2px;
}

.picker-tree-row {
  display: flex;
  align-items: center;
  padding: 0.35rem 0.6rem;
  border-radius: var(--fh-radius-sm, 0.375rem);
  cursor: pointer;
  color: var(--fh-text, #1e293b);
  font-size: var(--fh-text-md);
  transition: background-color var(--fh-transition-fast, 0.15s ease),
              color var(--fh-transition-fast, 0.15s ease),
              border-color var(--fh-transition-fast, 0.15s ease);
  border: 1px solid transparent;
  outline: none;
}

.picker-tree-row:hover {
  background-color: var(--fh-primary-soft, #eff6ff);
  color: var(--fh-primary);
}

.picker-tree-row:focus-visible {
  border-color: var(--fh-primary, #2563eb);
  box-shadow: var(--fh-focus-ring, 0 0 0 2px rgba(37, 99, 235, 0.25));
  background-color: var(--fh-soft, #f8fafc);
}

.picker-tree-row.is-selected {
  background-color: var(--fh-primary-soft, #eff6ff);
  border-color: var(--fh-primary-soft-border, #bfdbfe);
  color: var(--fh-primary-dark, #1d4ed8);
  font-weight: var(--fh-weight-semibold);
}

.picker-toggle {
  width: 22px;
  height: 22px;
  margin-right: 4px;
  border-radius: 4px;
  color: var(--fh-muted, #6b7280);
  transition: background-color 0.15s ease, color 0.15s ease;
  flex-shrink: 0;
}

.picker-toggle:not(.is-leaf):hover {
  background-color: rgba(0, 0, 0, 0.06);
  color: var(--fh-text, #1e293b);
}

.picker-caret {
  font-size: var(--fh-text-xs);
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  display: inline-block;
}

.picker-caret.is-expanded {
  transform: rotate(90deg);
}

.picker-folder-icon {
  font-size: var(--fh-text-lg);
  margin-right: 0.5rem;
  flex-shrink: 0;
  transition: transform 0.15s ease;
}

.picker-label {
  font-size: var(--fh-text-base);
  line-height: var(--fh-leading-snug);
  /* .flex-fill (flex: 1 1 auto) defaults to min-width: auto (= min-content),
     which silently defeats .text-truncate's ellipsis and can force the row —
     and any fluid grid/flex ancestor sized off it — wider than intended. */
  min-width: 0;
}

.picker-check-icon {
  font-size: var(--fh-text-base);
  flex-shrink: 0;
}

.tree-children.picker-children {
  margin-left: 0.75rem;
  padding-left: 0.75rem;
  border-left: 1px dashed var(--fh-border, #cbd5e1);
  margin-top: 2px;
}

.picker-no-children,
.picker-loading {
  font-size: var(--fh-text-sm);
  color: var(--fh-muted, #6b7280);
}

/* ==========================================================================
   FileHub overview screen — visual refactor (Bootstrap 5 + Font Awesome)
   ========================================================================== */
:root {
  /* Chrome brand — matched to SihubDrive_Overview.html (light shell,
     near-black ink, brighter blue). One palette for navbar, sidebar, well. */
  --fh-primary: #2563eb;
  --fh-primary-dark: #1d4ed8;
  --fh-border: #eaebef;
  --fh-muted: #6b7280;
  --fh-soft: #f7f8fa;
  --fh-bg: #f4f5f7;
  --fh-sidebar: #ffffff;
  --fh-sidebar-2: #f7f8fa;
  /* Hover/selected wash — same family as --fh-primary-soft so the drawer
     matches selected cards, list rows, and tree-picker rows. */
  --fh-sidebar-hover: #eff6ff;
  --fh-text: #14161a;
  --fh-ink: #14161a;
  /* Rendered .fh-navbar height. Declared here with the other chrome tokens
     so the shell's padding-top / drawer inset cannot resolve to unset
     before the later :root block that restates the same number. */
  --fh-header-h: 4.25rem;

  /* ---- Responsive scale tokens ------------------------------------------
     One place to reason about how the app grows, so individual components
     stop hard-coding their own pixel caps and drifting apart.

     The app's breakpoint ladder is 480 / 576 / 768 / 1024 / 1280 / 1536 /
     1920 / 2560 / 3840. Media queries use the `.98` upper bounds
     (575.98/767.98/1023.98/…) so a `max-width` rule and the `min-width` rule
     above it can never both match at the boundary — a viewport of exactly
     768px used to satisfy both `max-width: 768px` and the desktop defaults.

     --fh-shell-max  Widest the centered app shell is allowed to grow. Ramps
                     from "effectively full width" on a laptop to a capped
                     2880px on 4K, so ultra-wide and TV displays gain real
                     columns instead of framing a 1440px strip in grey.
     --fh-read-max   Cap for reading-width surfaces (search results)
                     where unbounded line length hurts rather than helps.
                     Grows more conservatively.
     --fh-gutter     Horizontal page padding, scaling with the viewport. */
  --fh-shell-max: clamp(1440px, 92vw, 2880px);
  --fh-read-max: clamp(1320px, 82vw, 2200px);
  --fh-gutter: clamp(0.75rem, 0.45rem + 1.1vw, 2.5rem);
}

/* --- 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
     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; }
}

.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. */
  position: relative;
  min-height: calc(100vh - var(--fh-header-h));
}

/* --- 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;
  }

  .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;
}

/* --- AJAX navigation progress bar ---------------------------------------
   Shown by browse.js's navigateTo() while a folder swap is in flight (with
   a short delay so a fast response never flashes it). Sits above the
   navbar's stacking context so it reads as a page-level loading signal. */
.fh-nav-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 100%;
  z-index: 1090;
  /* Purely decorative and sits directly over the navbar's top 3px — without
     this it would swallow clicks there (including on the hamburger) for the
     duration of every AJAX folder swap. */
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--fh-primary, #2563eb), transparent);
  background-size: 50% 100%;
  animation: fh-nav-progress-sweep 1.1s ease-in-out infinite;
}
@keyframes fh-nav-progress-sweep {
  0% { background-position: -50% 0; }
  100% { background-position: 150% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .fh-nav-progress { animation: none; background: var(--fh-primary, #2563eb); opacity: 0.6; }
}

/* --- Top navbar --------------------------------------------------------- */
.fh-navbar {
  background: #fff;
  border-bottom: 1px solid var(--fh-border);
}
.fh-nav-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
  margin-left: auto;
}

/* Hamburger. A real <button>, so it is focusable and Enter/Space-activated
   for free; the reset below just strips the UA chrome a <button> brings. */
.fh-burger {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 0; appearance: none;
  color: var(--fh-muted); border-radius: 0.625rem; padding: 0.5rem 0.6rem;
  width: 2.5rem; height: 2.5rem;
  line-height: var(--fh-leading-none); cursor: pointer;
}
.fh-burger:hover { background: var(--fh-soft); color: var(--fh-text); }
.fh-burger:focus-visible {
  outline: 2px solid var(--fh-primary);
  outline-offset: 2px;
}

.fh-brand { display: flex; align-items: center; }
.fh-brand a { display: flex; align-items: center; gap: 0.625rem; text-decoration: none; }
.fh-brand-mark {
  width: 1.875rem; height: 1.875rem; border-radius: 0.625rem;
  background: var(--fh-primary); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: var(--fh-text-sm);
}
.fh-brand-text {
  color: var(--fh-text);
  font-weight: var(--fh-weight-semibold);
  font-size: var(--fh-text-2xl);
  letter-spacing: var(--fh-tracking-tighter);
  line-height: var(--fh-leading-tight);
}
.fh-brand-logo {
  height: 1.75rem;
  width: auto;
  max-width: 7rem;
  object-fit: contain;
}
.fh-brand-badge {
  font-size: var(--fh-text-xs); color: var(--fh-muted); background: var(--fh-soft);
  padding: 2px 6px; border-radius: 0.25rem; letter-spacing: var(--fh-tracking-wide);
}

/* Grows with the navbar instead of stopping dead at 560px, which on a 3440px
   ultra-wide left the search box as a small island in a very empty header.
   min-width:0 (also set further down) lets it shrink below its content so the
   brand + action cluster can never force the header past the viewport. */
.fh-search { flex: 1 1 auto; max-width: 40rem; margin: 0; position: relative; min-width: 0; }
.fh-search-box {
  display: flex; align-items: center; gap: 0.625rem;
  background: #f7f8fa;
  border: 1px solid var(--fh-border);
  border-radius: 0.75rem;
  height: 2.75rem;
  padding: 0 0.5rem 0 1rem;
  overflow: visible;
  transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.fh-search-box:focus-within {
  background: #fff;
  border-color: #c7ccd6;
  box-shadow: 0 1px 4px rgba(20, 22, 26, 0.06);
}
.fh-search-icon { color: var(--fh-muted); margin: 0; font-size: var(--fh-text-md); }
.fh-search-input {
  flex: 1; border: 0; background: transparent; padding: 0 0.25rem;
  min-width: 0;
  font-size: var(--fh-text-base); color: var(--fh-text); outline: none;
}

/* Live search suggestions (P1-4) / history (P2-7) dropdown under the global
   search box. Positioned by JS-inserted markup, styled here. */
.fh-search-suggest {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 380px;
  overflow-y: auto;
  padding: 0.35rem;
  z-index: 1050;
  border: 1px solid var(--fh-border, #e2e8f0);
  border-radius: 0.65rem;
  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
  background: #fff;
}
.fh-search-suggest.show { display: block; }
.fh-search-suggest-item {
  border-radius: 0.375rem;
  padding: 0.45rem 0.65rem;
  font-size: var(--fh-text-base);
  color: var(--fh-text, #1e293b);
  transition: background-color 0.12s ease;
}
.fh-search-suggest-item.active,
.fh-search-suggest-item:hover {
  background-color: var(--fh-primary-soft, #eff6ff);
  color: var(--fh-primary, #2563eb);
}
.fh-search-suggest-item i { width: 1.1em; }

/* Term highlighting on /Search results (P1-6) */
mark { background: #fef08a; color: inherit; padding: 0 2px; border-radius: 3px; font-weight: var(--fh-weight-semibold); }

/* Shared with Admin Permissions (Views/Shared/_PermissionsWorkspace.cshtml,
   _UserAccessResult.cshtml) — do not scope these under .fh-search-container. */
.fh-search-table {
  font-size: var(--fh-text-sm);
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  margin: 0;
}

.fh-search-table thead th {
  background: #ffffff;
  color: var(--fh-muted, #6b7280);
  font-weight: var(--fh-weight-semibold);
  font-size: var(--fh-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--fh-border, #e2e8f0);
  border-top: none;
  vertical-align: middle;
}

.fh-search-table tbody tr {
  transition: background-color 0.12s ease;
}

.fh-search-table tbody tr:hover td {
  background-color: var(--fh-primary-soft, #eff6ff);
}

.fh-search-table tbody td {
  padding: 0.7rem 1rem;
  vertical-align: middle;
  border-bottom: 1px solid #f1f5f9;
  color: #334155;
}

.fh-search-table tbody tr:last-child td {
  border-bottom: none;
}

.fh-search-empty {
  text-align: center;
  padding: 4rem 1.5rem;
  background: #ffffff;
  border: 1px solid var(--fh-border, #e2e8f0);
  border-radius: 0.85rem;
}

.fh-search-empty-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: #eff6ff;
  color: var(--fh-primary, #2563eb);
  font-size: var(--fh-text-4xl);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1rem;
}

.fh-search-empty-icon.is-muted {
  background: #f1f5f9;
  color: var(--fh-muted);
}

.fh-search-empty-title {
  font-size: var(--fh-text-xl);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text, #1e293b);
  margin-bottom: 0.35rem;
}

.fh-search-empty-subtitle {
  font-size: var(--fh-text-sm);
  color: var(--fh-muted, #6b7280);
  max-width: 440px;
  margin: 0 auto 1.25rem;
}

/* --- Search page (/drive/search) — scoped so navbar .fh-search and /drive
   browse are untouched. Tokens only; hide-column ladder is the shared
   .fh-col-* rules further down. ------------------------------------------ */
.fh-search-container {
  width: 100%;
  max-width: var(--fh-read-max, 1320px);
  margin: 0 auto;
  min-width: 0;
}

.fh-search-container .fh-search-form {
  display: flex;
  flex-direction: column;
  gap: var(--fh-section-gap, 1.1rem);
  min-width: 0;
}

.fh-search-container .fh-search-toolbar-main {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  flex: 1 1 auto;
  min-width: 0;
}

.fh-search-container .fh-search-query {
  display: flex;
  align-items: center;
  flex: 1 1 16rem;
  min-width: 0;
  background: var(--fh-soft);
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-lg, 0.75rem);
  padding: 0 0.15rem 0 0.75rem;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}

.fh-search-container .fh-search-query:focus-within {
  background: #ffffff;
  border-color: var(--fh-primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

.fh-search-container .fh-search-query-icon {
  color: var(--fh-muted);
  font-size: var(--fh-text-md);
  flex-shrink: 0;
}

.fh-search-container .fh-search-query-field {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  padding: 0.5rem 0.6rem;
  font-size: var(--fh-text-md);
  color: var(--fh-text);
  outline: none;
}

.fh-search-container .fh-search-query-submit {
  flex-shrink: 0;
}

.fh-search-container .fh-search-toolbar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex: 0 1 auto;
  flex-wrap: wrap;
  min-width: 0;
}

.fh-search-container .fh-search-filter-menu {
  width: min(320px, calc(100vw - 1.5rem));
}

.fh-search-container .fh-search-chips {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: wrap;
  min-width: 0;
}

.fh-search-container .fh-search-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-medium);
  padding: 0.2rem 0.55rem;
  border-radius: 9999px;
  background-color: var(--fh-soft);
  border: 1px solid var(--fh-border);
  color: var(--fh-text);
  max-width: 100%;
}

.fh-search-container .fh-search-chip.is-scope {
  background-color: #eff6ff;
  border-color: #bfdbfe;
  color: var(--fh-primary);
}

.fh-search-container .fh-search-chip-remove {
  color: var(--fh-muted);
  text-decoration: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  min-height: 1.25rem;
  transition: color 0.12s ease;
}

.fh-search-container .fh-search-chip-remove:hover {
  color: #ef4444;
}

.fh-search-container .fh-search-status {
  margin: 0;
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
}

.fh-search-container .fh-search-col-name {
  min-width: 0;
}

.fh-search-container .fh-search-name,
.fh-search-container .fh-search-name-link {
  border: 0;
  background: transparent;
  padding: 0;
  max-width: 100%;
  font-weight: var(--fh-weight-medium);
  color: var(--fh-text);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  display: inline-block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: color 0.12s ease;
}

.fh-search-container .fh-search-name:hover,
.fh-search-container .fh-search-name-link:hover {
  color: var(--fh-primary);
}

.fh-search-container .fh-search-col-path {
  max-width: 16rem;
}

.fh-search-container .fh-search-path {
  display: block;
  max-width: 16rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fh-search-container .fh-search-group th {
  background: var(--fh-soft);
  color: var(--fh-muted);
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  padding: 0.45rem 1rem;
  border-bottom: 1px solid var(--fh-border);
}
.fh-search-container .fh-list-card table.table-hover > tbody > tr.fh-search-group:hover > * {
  background-color: var(--fh-primary-soft, #eff6ff);
}

.fh-search-container .fh-search-row-actions {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.1rem;
}
.fh-search-container a.fh-icon-btn {
  text-decoration: none;
}

.fh-search-container .fh-search-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding: 0.65rem 1rem;
  border-top: 1px solid var(--fh-border);
  background: var(--fh-soft);
}

.fh-search-container .fh-search-pager-nav {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

@media (max-width: 767.98px) {
  .fh-search-container .fh-search-query {
    flex-basis: 100%;
  }
  .fh-search-container .fh-search-toolbar {
    flex-basis: 100%;
  }
}

@media (max-width: 575.98px) {
  .fh-search-container .fh-search-col-path,
  .fh-search-container .fh-search-path {
    max-width: 7rem;
  }
  /* Browse shrinks .fh-col-actions to 3rem for a single ⋮; search keeps
     Preview + Download as 44px targets. */
  .fh-search-container .fh-col-actions {
    width: auto;
  }
}

.fh-btn-primary {
  background: var(--fh-primary); border-color: var(--fh-primary); color: #fff;
  border-radius: 0.5rem; padding: 0.45rem 0.9rem; font-size: var(--fh-text-base); font-weight: var(--fh-weight-medium);
}
.fh-btn-primary:hover { background: var(--fh-primary-dark); border-color: var(--fh-primary-dark); color: #fff; }

.fh-icon-btn {
  width: 2.5rem; height: 2.5rem; border: 0; background: transparent; color: var(--fh-muted);
  border-radius: 0.75rem; display: flex; align-items: center; justify-content: center; position: relative;
}
.fh-icon-btn:hover { background: var(--fh-primary-soft, #eff6ff); color: var(--fh-primary); }
.fh-icon-btn:active { background: var(--fh-primary-soft, #eff6ff); color: var(--fh-primary-dark); }
.fh-icon-btn.text-danger:hover,
.fh-icon-btn.text-danger:active {
  background: rgba(220, 38, 38, 0.08);
  color: var(--fh-danger);
}
.fh-dot {
  position: absolute; top: 7px; right: 7px; width: 8px; height: 8px;
  border-radius: 50%; background: #ef4444; border: 2px solid #fff;
}
/* Navbar language toggle pill — segmented inline VN | US flag icons */
.fh-lang-toggle {
  display: inline-flex;
  align-items: center;
  background: #f2f3f6;
  border: 0;
  border-radius: 0.625rem;
  padding: 3px;
  height: 2rem;
  box-sizing: border-box;
}

.fh-lang-toggle form {
  margin: 0;
  display: inline-flex;
}

.fh-lang-btn {
  border: 0;
  background: transparent;
  width: 34px;
  height: 26px;
  padding: 0;
  border-radius: 0.45rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s ease-in-out;
  cursor: pointer;
  box-sizing: border-box;
}

.fh-lang-btn:hover:not(.active) {
  background: rgba(0, 0, 0, 0.04);
}

.fh-lang-btn.active {
  background: #fff;
  box-shadow: 0 1px 2px rgba(20, 22, 26, 0.1);
  cursor: default;
}

.fh-lang-btn:focus-visible {
  outline: 2px solid var(--fh-primary);
  outline-offset: 1px;
}

/* Flag icon wrapper, Font Awesome and inline SVG styles */
.fh-flag-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  line-height: var(--fh-leading-none);
  font-size: var(--fh-text-lg);
  transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out;
}

.fh-flag-icon i {
  display: inline-block;
  line-height: var(--fh-leading-none);
  font-size: var(--fh-text-lg);
}

.fh-flag-svg {
  width: 18px;
  height: 18px;
  display: block;
  flex-shrink: 0;
}

.fh-lang-btn:not(.active) .fh-flag-icon {
  opacity: 0.55;
}

.fh-lang-btn:hover:not(.active) .fh-flag-icon {
  opacity: 1;
  transform: scale(1.05);
}

.fh-lang-btn.active .fh-flag-icon {
  opacity: 1;
  filter: none;
}

/* Navbar storage meter pill (mockup) — icon, slim progress bar, "used / quota"
   label, all inline. .fh-storage-meter-bar/-fill are deliberately separate
   from _UsageBar's .fh-storage-bar (that one is a multi-segment used/trash/free
   breakdown for the Storage pages; this is a single-fraction glance). */
.fh-storage-meter {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--fh-border);
  border-radius: var(--bs-border-radius-pill, 50rem);
  color: var(--fh-muted);
  font-size: var(--fh-text-xs);
}
.fh-storage-meter > i { font-size: var(--fh-text-sm); }
.fh-storage-meter-bar {
  width: 70px;
  height: 5px;
  border-radius: 999px;
  background: var(--fh-soft);
  overflow: hidden;
}
.fh-storage-meter-fill {
  display: block;
  height: 100%;
  background: var(--fh-primary);
  border-radius: inherit;
}
.fh-storage-meter-over .fh-storage-meter-fill { background: var(--fh-danger); }
.fh-storage-meter-label {
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  white-space: nowrap;
}
a.fh-storage-meter {
  text-decoration: none;
}
a.fh-storage-meter:hover {
  background: var(--fh-soft);
  color: var(--fh-muted);
}

.fh-user-btn {
  display: flex; align-items: center; gap: 0.625rem; border: 0; background: transparent;
  height: 2.75rem; padding: 0 0.625rem 0 0.375rem; border-radius: 0.75rem;
  text-align: left;
}
.fh-user-btn:hover { background: #f2f3f6; }
.fh-avatar {
  width: 2rem; height: 2rem; border-radius: 0.625rem;
  background: var(--fh-primary); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fh-text-xs); font-weight: var(--fh-weight-semibold); letter-spacing: var(--fh-tracking-wide);
}
.fh-user-name { display: block; font-size: var(--fh-text-sm); font-weight: var(--fh-weight-medium); color: var(--fh-text); line-height: var(--fh-leading-tight); }
.fh-user-role { display: block; font-size: var(--fh-text-xs); color: var(--fh-muted); line-height: var(--fh-leading-tight); }
.fh-user-btn .fh-user-role .badge {
  background: none; color: var(--fh-muted); font-weight: var(--fh-weight-medium);
  font-size: var(--fh-text-xs); padding: 0; letter-spacing: var(--fh-tracking-normal);
}
.fh-user-btn > .fa-chevron-down { font-size: var(--fh-text-2xs); color: var(--fh-muted); }

/* The fixed `.fh-navbar`/`.fh-sidebar` sit at 1040-1050 (see the z-index
   ladder in the app-shell block), above Bootstrap's default
   `--bs-dropdown-zindex: 1000` — without this, a menu opened near the top of
   the page (first grid row/table row, right under the sticky navbar) would
   render behind that chrome and appear clipped. 1060 clears all of it. */
.fh-dropdown {
  z-index: 1060 !important;
  border: 1px solid var(--fh-border);
  border-radius: 0.5rem;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);
  max-height: min(75vh, 26rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  right: auto !important;
  bottom: auto !important;
}
@media (max-height: 600px) {
  .fh-dropdown {
    max-height: min(80vh, 18rem);
  }
}
.fh-dropdown .dropdown-item { font-size: var(--fh-text-base); padding: 0.5rem 0.75rem; }
.fh-dropdown .dropdown-item:hover { background: var(--fh-soft); }
.fh-dropdown .dropdown-header { font-size: var(--fh-text-sm); }
/* Filter dropdown is sized so the two date inputs sit side by side. It used to
   be a flat `width: 300px`, which on a 360px phone left each date field about
   135px — narrower than a WebKit `<input type="date">` can render — so the
   pair overflowed the menu. Now it prefers 300px but yields to the viewport,
   and the date row is allowed to stack once the fields can't fit side by
   side (see .fh-filter-menu .d-flex below). */
.fh-filter-menu {
  width: min(300px, calc(100vw - 1.5rem));
  max-width: calc(100vw - 1.5rem);
}
/* Breakpoint-free: the date row wraps when — and only when — the two fields
   can no longer both meet their minimum legible width, whatever the menu's
   actual width turns out to be. */
.fh-filter-menu .d-flex {
  flex-wrap: wrap;
}
.fh-filter-menu .d-flex > .form-control {
  flex: 1 1 8.5rem;
  min-width: 0;
}

/* --- Sortable list-view column headers (sort moved from the toolbar into
   the table) — the active column renders a direction arrow via
   .fh-sort-arrow; aria-sort carries the same state for assistive tech. */
.fh-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.fh-sortable:hover { color: var(--fh-primary); }
.fh-sort-arrow { color: var(--fh-primary); font-size: var(--fh-text-2xs); }

/* Filter button when filters are active — visually distinct from a plain
   secondary button (alongside the ● badge) until the user clears them. */
.fh-filter-active { border-color: var(--fh-primary); color: var(--fh-primary); }
.fh-filter-active:hover { background: var(--fh-soft); }

/* --- Sidebar nav -------------------------------------------------------- */
.fh-sidebar-new-wrapper {
  margin: 1.125rem 0.75rem 0.35rem;
  display: flex;
  justify-content: center;
}

.fh-sidebar-new {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  min-height: 3rem;
  width: auto;
  min-width: 7.75rem;
  max-width: 10.5rem;
  padding: 0.625rem 1.25rem;
  border-radius: 1.5rem;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
  color: #fff;
  font-size: var(--fh-text-md);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-tight);
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  box-shadow: 0 3px 10px rgba(37, 99, 235, 0.28), 0 1px 3px rgba(37, 99, 235, 0.16);
  transition: all 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}
.fh-sidebar-new:hover {
  background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
  color: #fff;
  transform: translateY(-1.5px);
  box-shadow: 0 5px 14px rgba(37, 99, 235, 0.38), 0 2px 4px rgba(37, 99, 235, 0.2);
}
.fh-sidebar-new:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(37, 99, 235, 0.25);
}
.fh-sidebar-new:focus-visible {
  outline: 2px solid var(--fh-primary);
  outline-offset: 2px;
}
.fh-sidebar-new:disabled,
.fh-sidebar-new[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
  box-shadow: none;
  transform: none;
}
.fh-sidebar-new.dropdown-toggle::after {
  margin-left: 0.35rem;
  vertical-align: 0.125em;
}

.fh-sidebar-new-menu {
  min-width: 12.5rem;
  padding: 0.375rem;
  border-radius: 0.75rem;
}

.fh-sidebar-nav { padding: 0.5rem 0.75rem 0.5rem; }
.fh-nav-heading { display: none; }
/* The menu supplied its own list reset, flex column and link box via
   `.nav.nav-pills.sidebar-menu`; it owns all three directly now. */
.fh-sidebar-menu { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.fh-sidebar-menu .nav-link {
  display: flex; align-items: center; gap: 0.875rem;
  min-height: 2.5rem;
  padding: 0 0.875rem;
  color: var(--fh-muted); border-radius: 0.625rem; margin-bottom: 0;
  font-size: var(--fh-text-base); letter-spacing: var(--fh-tracking-tight);
  text-decoration: none;
  transition: background-color 0.14s ease, color 0.14s ease;
}
.fh-sidebar-menu .nav-link > p { margin: 0; flex: 1 1 auto; display: flex; align-items: center; font-weight: inherit; }
.fh-sidebar-menu .nav-link:hover {
  color: var(--fh-primary);
  background: var(--fh-primary-soft, var(--fh-sidebar-hover));
}
.fh-sidebar-menu .nav-link:active {
  color: var(--fh-primary-dark);
  background: var(--fh-primary-soft, var(--fh-sidebar-hover));
}
.fh-sidebar-menu .nav-link.active {
  background: var(--fh-primary-soft, var(--fh-sidebar-hover));
  color: var(--fh-primary);
  font-weight: var(--fh-weight-semibold);
}
.fh-sidebar-menu .nav-link.active:hover,
.fh-sidebar-menu .nav-link.active:active {
  color: var(--fh-primary-dark);
  background: var(--fh-primary-soft, var(--fh-sidebar-hover));
}
.fh-sidebar-menu .nav-icon { color: inherit; width: 1.25rem; text-align: center; flex: 0 0 auto; font-size: var(--fh-text-lg); }
.fh-sidebar-menu .nav-link:focus-visible {
  outline: 2px solid var(--fh-primary);
  outline-offset: 2px;
}

.fh-sidebar-footer {
  flex: 0 0 auto;
  padding: 1rem 0.875rem 1.25rem;
  border-top: 1px solid var(--fh-border);
}
.fh-sidebar-footer .fh-storage-meter {
  width: 100%;
  flex-wrap: wrap;
  border: 0;
  border-radius: 0;
  padding: 0;
  gap: 0.55rem 0.5rem;
}
.fh-sidebar-footer .fh-storage-meter-bar {
  width: 100%;
  order: 3;
  height: 5px;
  background: #eef0f3;
}
.fh-sidebar-footer .fh-storage-meter-label {
  font-weight: var(--fh-weight-regular);
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
}
.fh-sidebar-footer .fh-storage-meter > i { display: none; }

/* --- Sidebar submenus (Admin / My Department) ---------------------------
   A plain disclosure: a <button> owning aria-expanded, and a sibling list
   shown by the `is-open` class on the <li>. Replaces the treeview widget the
   vendor script used to provide, and unlike it the toggle is a real button
   rather than an `href="#"` anchor, so it never pushes a history entry or
   jumps the page when activated. */
.fh-sub-toggle {
  width: 100%;
  background: none; border: 0; appearance: none;
  font: inherit; text-align: left; cursor: pointer;
}
.fh-sub-caret {
  margin-left: auto;
  font-size: var(--fh-text-xs);
  transition: transform 150ms ease;
}
.fh-has-sub.is-open > .fh-sub-toggle .fh-sub-caret { transform: rotate(-90deg); }

.fh-submenu {
  list-style: none;
  margin: 0 0 2px;
  padding: 0 0 0 1.4rem;
  display: none;
}
.fh-has-sub.is-open > .fh-submenu { display: block; }
.fh-submenu .nav-link { font-size: var(--fh-text-base); padding: 0.4rem 0.75rem; }
.fh-submenu .nav-icon { font-size: var(--fh-text-2xs); }

@media (prefers-reduced-motion: reduce) {
  .fh-sub-caret { transition: none; }
}

/* --- Browse content -----------------------------------------------------
   Section rhythm lives on .fh-panel (nested browse/shared panels and
   single-layer surfaces like Home/Search). The layout .fh-content well
   keeps page padding/background only — see the consolidated rule below. */
.fh-panel {
  display: flex;
  flex-direction: column;
  gap: var(--fh-section-gap, 1.1rem);
  min-width: 0;
}

/* --- Modern & Responsive Breadcrumb (.fh-breadcrumb) -------------------- */
.fh-breadcrumb {
  display: flex;
  align-items: center;
  margin: 0 0 0.35rem 0;
  padding: 0;
  min-width: 0;
  width: 100%;
}

.fh-breadcrumb-list {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  list-style: none;
  margin: 0;
  padding: 0;
  flex-wrap: nowrap;
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE/Edge */
}

.fh-breadcrumb-list::-webkit-scrollbar {
  display: none; /* Chrome/Safari */
}

.fh-breadcrumb-item {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  flex-shrink: 1;
}

.fh-breadcrumb-item:first-child {
  flex-shrink: 0;
}

.fh-breadcrumb-item:last-child {
  flex-shrink: 0;
  min-width: 0;
}

.fh-breadcrumb-link {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--fh-muted, #6b7280);
  text-decoration: none;
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-medium);
  padding: 0.2rem 0.45rem;
  border-radius: 0.375rem;
  max-width: 180px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 0.15s ease, background-color 0.15s ease;
  outline: none;
}

.fh-breadcrumb-link:hover {
  color: var(--fh-primary, #2563eb);
  background-color: rgba(37, 99, 235, 0.08);
}

.fh-breadcrumb-link:focus-visible {
  color: var(--fh-primary-dark, #1d4ed8);
  background-color: var(--fh-soft, #f8fafc);
  box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.35);
}

.fh-breadcrumb-current {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--fh-text, #1e293b);
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-semibold);
  padding: 0.2rem 0.55rem;
  border-radius: 0.375rem;
  background-color: var(--fh-soft, #f8fafc);
  border: 1px solid var(--fh-border, #e2e8f0);
  max-width: 220px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fh-breadcrumb-separator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--fh-muted);
  font-size: var(--fh-text-2xs);
  flex-shrink: 0;
  user-select: none;
  opacity: 0.8;
  margin: 0 0.1rem;
}

.fh-breadcrumb-home-icon {
  font-size: var(--fh-text-xs);
  flex-shrink: 0;
}

/* Fallback for unnested/legacy markup */
.fh-breadcrumb a:not(.fh-breadcrumb-link) {
  color: var(--fh-muted, #6b7280);
  text-decoration: none;
  font-size: var(--fh-text-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fh-breadcrumb .current:not(.fh-breadcrumb-current) {
  color: var(--fh-text, #1e293b);
  font-weight: var(--fh-weight-semibold);
  font-size: var(--fh-text-sm);
}

/* Responsive adjustments (.98 upper bound — see the breakpoint note on
   :root / --fh-read-max above). */
@media (max-width: 767.98px) {
  .fh-breadcrumb-link {
    max-width: 120px;
    font-size: var(--fh-text-xs);
  }
  .fh-breadcrumb-current {
    max-width: 160px;
    font-size: var(--fh-text-xs);
  }
}

@media (max-width: 575.98px) {
  .fh-breadcrumb-list {
    gap: 0.2rem;
  }
  .fh-breadcrumb-link {
    max-width: 80px;
    padding: 0.15rem 0.3rem;
    font-size: var(--fh-text-xs);
  }
  .fh-breadcrumb-current {
    max-width: 130px;
    padding: 0.15rem 0.4rem;
    font-size: var(--fh-text-xs);
  }
  .fh-breadcrumb-separator {
    font-size: var(--fh-text-2xs);
    margin: 0 0.05rem;
  }
  .fh-breadcrumb-item.crumb-intermediate .fh-breadcrumb-link {
    max-width: 55px;
  }
}

/* Toolbar: Visually lighter, transparent stage framing. On wide screens this
   is the right-hand cluster of .fh-content-head-main, sized to its contents and
   sitting opposite the page title; below 768px it wraps to a full-width row of
   its own (see the media query in the Focused browse surface section). Its two
   groups — .fh-toolbar-group (view/filter controls) and
   .fh-toolbar-group-end (the primary "+ New" action) — wrap as units rather
   than every control reflowing individually. */
.fh-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex: 0 1 auto;
  gap: 0.6rem;
  flex-wrap: wrap;
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
}
.fh-toolbar-group {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}
/* Belt-and-suspenders alongside .fh-toolbar's justify-content (flex-end when
   inline beside the title, space-between once it wraps to its own row) — keeps
   the primary action pinned right in both cases, and even if a future edit adds
   a third group before it. */
.fh-toolbar-group-end {
  margin-left: auto;
}
.fh-toolbar .btn {
  font-size: var(--fh-text-sm);
  border-radius: 0.5rem;
}
.fh-toolbar .btn-outline-secondary {
  background: #fff;
  border-color: var(--fh-border);
  color: var(--fh-muted);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
  transition: all 0.15s ease;
}
.fh-toolbar .btn-outline-secondary:hover {
  background: var(--fh-primary-soft, #eff6ff);
  border-color: var(--fh-primary-soft-border, #bfdbfe);
  color: var(--fh-primary);
}

/* "+ New" primary action — the single most important CTA on the toolbar,
   sized and shadowed up to read unmistakably as primary. */
.fh-new-btn {
  font-size: var(--fh-text-md);
  font-weight: var(--fh-weight-bold);
  padding: 0.55rem 1.3rem;
  border-radius: 0.6rem;
  box-shadow: 0 2px 8px rgba(37, 99, 235, 0.35);
  transition: all 0.15s ease;
}
.fh-new-btn:hover {
  transform: translateY(-1.5px);
  box-shadow: 0 6px 16px rgba(37, 99, 235, 0.4);
}
.fh-new-btn:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(37, 99, 235, 0.3);
}

/* View toggle: sleek segmented control */
.fh-view-toggle {
  border: 1px solid var(--fh-border);
  border-radius: 0.55rem;
  overflow: hidden;
  display: inline-flex;
  background: #f1f5f9;
  padding: 2px;
  gap: 2px;
}
.fh-view-toggle .btn {
  border: 0;
  border-radius: 0.4rem;
  background: transparent;
  color: var(--fh-muted);
  font-weight: var(--fh-weight-medium);
  font-size: var(--fh-text-xs);
  padding: 0.32rem 0.65rem;
  transition: all 0.15s ease;
}
.fh-view-toggle .btn:not(:last-child) {
  border-right: none;
}
.fh-view-toggle .btn:hover {
  color: var(--fh-primary);
}
.fh-view-toggle .btn.active {
  background: #ffffff;
  color: var(--fh-primary);
  font-weight: var(--fh-weight-semibold);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
}
.fh-view-toggle .btn.active:hover {
  color: var(--fh-primary-dark);
}
/* Item count — a quiet chip pinned beside the page title, so it reads as
   metadata belonging to the title rather than a heading of its own. Never
   shrinks or wraps; the title ellipsizes instead. */
.fh-count {
  flex-shrink: 0;
  padding: 0.15rem 0.6rem;
  background: var(--fh-soft);
  border: 1px solid var(--fh-border);
  border-radius: var(--bs-border-radius-pill, 50rem);
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
  font-weight: var(--fh-weight-medium);
  letter-spacing: var(--fh-tracking-wide);
  white-space: nowrap;
}

/* Grid: Hero Content Stage. Horizontal inset shares .fh-content-head's
   `--fh-head-inset` token so cards line up under the header text instead of
   sitting flush against the page edge while the header is indented. The base
   rule below is the explicit fallback — the responsive ladder covers every
   width. At 2560px the root font-size also steps up, so column count drops
   twice there by design (track minimum in px + rem-based type ramp). */
.fh-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--fh-grid-gap, 1.1rem);
  padding: 0 var(--fh-head-inset, 0.25rem);
}

@media (max-width: 575.98px) {
  .fh-grid {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  }
}

@media (min-width: 576px) and (max-width: 767.98px) {
  .fh-grid {
    grid-template-columns: repeat(auto-fill, minmax(175px, 1fr));
  }
}

@media (min-width: 768px) and (max-width: 1023.98px) {
  .fh-grid {
    grid-template-columns: repeat(auto-fill, minmax(195px, 1fr));
  }
}

@media (min-width: 1024px) and (max-width: 1439.98px) {
  .fh-grid {
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  }
}

@media (min-width: 1440px) and (max-width: 1919.98px) {
  .fh-grid {
    grid-template-columns: repeat(auto-fill, minmax(225px, 1fr));
  }
}

@media (min-width: 1920px) and (max-width: 2559.98px) {
  .fh-grid {
    grid-template-columns: repeat(auto-fill, minmax(245px, 1fr));
  }
}

@media (min-width: 2560px) and (max-width: 3839.98px) {
  .fh-grid {
    grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
  }
}

@media (min-width: 3840px) {
  .fh-grid {
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  }
}

/* Grid view is split into a Folders section and a Files section (mockup) —
   #grid-view itself is now just a vertical stack of the two; each section's
   .fh-grid above is the actual card grid. Shares --fh-section-gap so the
   folders→files seam matches every other seam on the page. */
.fh-grid-sections {
  display: flex;
  flex-direction: column;
  gap: var(--fh-section-gap, 1.1rem);
}
.fh-grid-section[hidden] { display: none; }

/* Infinite scroll (Browse) */
#feed-sentinel { height: 1px; width: 100%; }
.fh-feed-status {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 2.5rem;
  padding: 0;
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
}
.fh-feed-error { color: var(--fh-danger, #dc2626); }

/* Grid Cards */
.fh-card {
  position: relative;
  background: #ffffff;
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-xl, 0.85rem);
  padding: 1rem;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  min-height: 8rem;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.03);
  transition: box-shadow 0.2s cubic-bezier(0.16, 1, 0.3, 1),
              border-color 0.2s ease,
              background-color 0.2s ease;
  user-select: none;
  -webkit-user-select: none;
}
.fh-card:hover {
  border-color: var(--fh-primary-soft-border, #bfdbfe);
  background-color: var(--fh-primary-soft, #eff6ff);
  box-shadow: 0 10px 24px -4px rgba(37, 99, 235, 0.08), 0 4px 8px -2px rgba(37, 99, 235, 0.04);
}
.fh-card:active {
  color: var(--fh-primary-dark);
  box-shadow: 0 4px 12px -2px rgba(37, 99, 235, 0.06);
}

@media (max-width: 575.98px) {
  .fh-card {
    padding: 0.75rem;
    min-height: 6.875rem;
    border-radius: var(--fh-radius-xl, 0.75rem);
  }
}

/* Click-to-select (Google Drive style) */
.fh-card.is-selected {
  border-color: var(--fh-primary);
  background-color: var(--fh-selected-bg, #f0f7ff);
  box-shadow: 0 0 0 1.5px var(--fh-primary), 0 4px 14px rgba(37, 99, 235, 0.12);
}
.fh-card.is-selected:hover {
  border-color: var(--fh-primary);
  box-shadow: 0 0 0 1.5px var(--fh-primary), 0 8px 22px rgba(37, 99, 235, 0.18);
}
/* Ensure .fh-card never acts as containing block or stacking context for
   position: fixed dropdown menus. Deliberately no z-index here: cards are
   grid items that never overlap each other, so painting above a sibling was
   never the point, and a z-index on a positioned element creates a stacking
   context that would cap the fixed .fh-dropdown (1060) back down to whatever
   this rule said — including, previously, tying it with .fh-navbar (1050)
   and letting an open card's menu paint over the hamburger while scrolled
   under the fixed header. */
.fh-card:has(.dropdown-menu.show),
.fh-card:has([aria-expanded="true"]),
.fh-card.has-open-menu {
  position: relative;
  transform: none !important;
  transition: none !important;
}
.fh-card-icon {
  width: 44px;
  height: 44px;
  border-radius: 0.7rem;
  background: var(--fh-soft);
  border: 1px solid rgba(226, 232, 240, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0.75rem;
  font-size: var(--fh-text-2xl);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.fh-card:hover .fh-card-icon {
  transform: scale(1.05);
}
/* Per-type tinted icon tiles — shared with the upload dock's item list
   (.fh-upload-item-icon), one declaration per type serving both surfaces so
   the palette can't drift between them. FileTypeDisplay.Group() supplies the
   browse-side `icon-*` class (document/spreadsheet/presentation/image/
   archive/video/audio/other); `icon-folder` is browse-only. */
.fh-upload-item-icon.icon-image, .fh-card-icon.icon-image { background: #e0f2fe; color: #0284c7; }
.fh-upload-item-icon.icon-pdf { background: #ffe4e6; color: #e11d48; }
.fh-upload-item-icon.icon-archive, .fh-card-icon.icon-archive { background: #fef3c7; color: #d97706; }
.fh-upload-item-icon.icon-code { background: #dcfce7; color: #059669; }
.fh-upload-item-icon.icon-doc, .fh-card-icon.icon-document { background: #dbeafe; color: #2563eb; }
.fh-upload-item-icon.icon-excel, .fh-card-icon.icon-spreadsheet { background: #dcfce7; color: #16a34a; }
.fh-upload-item-icon.icon-presentation, .fh-card-icon.icon-presentation { background: #ffedd5; color: #ea580c; }
.fh-upload-item-icon.icon-text, .fh-card-icon.icon-other { background: #f1f5f9; color: var(--fh-muted); }
.fh-upload-item-icon.icon-video, .fh-card-icon.icon-video { background: #f3e8ff; color: #9333ea; }
.fh-upload-item-icon.icon-audio, .fh-card-icon.icon-audio { background: #fdf2f8; color: #db2777; }
.fh-card-icon.icon-folder { background: rgba(245, 158, 11, 0.12); color: #f59e0b; }
.fh-card-name {
  font-size: var(--fh-text-base);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  line-height: var(--fh-leading-snug);
  margin-bottom: 0.35rem;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-word;
}
.fh-card-name a,
.fh-card-name button {
  color: inherit;
  text-decoration: none;
}
/* A file card's name is a <button> (it opens the preview modal). Without this
   it renders with the UA's border/background/padding, and its block-ish box
   also defeats the -webkit-line-clamp above — hence `display: inline`. */
.fh-card-name button {
  display: inline;
  border: 0;
  background: transparent;
  padding: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.fh-card-name a:hover,
.fh-card-name button:hover {
  color: var(--fh-primary);
}

/* Card Thumbnails (Inline Image & Video Preview in Grid View) */
.fh-card-thumb {
  position: relative;
  width: 100%;
  /* Was a flat `height: 120px`. The card's width is fluid (auto-fill track),
     so a fixed height meant the thumbnail letterboxed harder the wider the
     card got — on a 4K grid a 300px-wide card showed its preview through a
     120px slot. A ratio keeps the preview proportional to the card at every
     breakpoint; the clamp stops it from becoming a tall panel on the widest
     cards or collapsing on the narrowest. */
  aspect-ratio: 4 / 3;
  height: auto;
  min-height: 5.5rem;
  max-height: 15rem;
  border-radius: 0.65rem;
  background: var(--fh-soft, #f8fafc);
  border: 1px solid rgba(226, 232, 240, 0.7);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0.75rem;
  flex-shrink: 0;
  user-select: none;
  -webkit-user-select: none;
}

.fh-card-thumb-media {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}

.fh-card-thumb-media.fh-card-thumb-media--contain {
  object-fit: contain;
  background: #ffffff;
  padding: 4px;
}

.fh-card:hover .fh-card-thumb-media {
  transform: scale(1.04);
}

.fh-card-thumb-canvas {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  background: #ffffff;
  padding: 4px;
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}

.fh-card:hover .fh-card-thumb-canvas {
  transform: scale(1.04);
}

.fh-card-thumb--pdf {
  background: #f8fafc;
}

/* An unsized <canvas> defaults to 300x150 and would flash as a blank white sheet
   (the canvas paints its own white background) before pdf.js has drawn page 1.
   Keep it hidden until the render lands. */
.fh-card-thumb--pdf:not(.is-rendered) .fh-card-thumb-canvas {
  visibility: hidden;
}

/* Soft skeleton shimmer while pdf.js fetches and rasterises the first page. */
.fh-card-thumb--pdf.is-loading {
  background-image: linear-gradient(100deg, rgba(226, 232, 240, 0) 30%, rgba(226, 232, 240, 0.85) 50%, rgba(226, 232, 240, 0) 70%);
  background-size: 220% 100%;
  background-repeat: no-repeat;
  animation: fh-thumb-skeleton 1.4s ease-in-out infinite;
}

@keyframes fh-thumb-skeleton {
  0% {
    background-position: 130% 0;
  }
  100% {
    background-position: -30% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fh-card-thumb--pdf.is-loading {
    animation: none;
    background-image: none;
    background-color: var(--fh-soft, #f8fafc);
  }
}

/* Audio Card (Hash-colored gradient, icon, title, play badge) */
.fh-card-audio {
  background: var(--fh-audio-gradient, linear-gradient(135deg, #4f46e5, #ec4899));
  color: #ffffff;
  padding: 0.75rem;
}

.fh-card-audio-cover {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  width: 100%;
  pointer-events: none;
}

.fh-card-audio-icon {
  font-size: var(--fh-text-4xl);
  margin-bottom: 0.35rem;
  color: rgba(255, 255, 255, 0.95);
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.25));
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}

.fh-card:hover .fh-card-audio-icon {
  transform: scale(1.08);
}

.fh-card-audio-title {
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  max-width: 90%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #ffffff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  opacity: 0.95;
}

.fh-card-audio-play {
  position: absolute;
  bottom: 0.45rem;
  right: 0.45rem;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  border: none;
  color: #0f172a;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-sm);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), background-color 0.2s ease, box-shadow 0.2s ease;
  z-index: 2;
  padding-left: 2px;
}

.fh-card-audio-play:hover {
  transform: scale(1.12);
  background: #ffffff;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
  color: var(--fh-primary, #2563eb);
}

/* Snippet Cards (Text / Code / Markdown ~12 lines with bottom mask fade-out) */
.fh-card-thumb--snippet {
  background: var(--fh-soft, #f8fafc);
  cursor: pointer;
  align-items: stretch;
  justify-content: stretch;
}

.fh-card-snippet-content {
  width: 100%;
  height: 100%;
  padding: 0.55rem 0.65rem;
  overflow: hidden;
  text-align: left;
  font-size: var(--fh-text-xs);
  line-height: var(--fh-leading-snug);
  color: var(--fh-text, #1e293b);
  -webkit-mask-image: linear-gradient(to bottom, black 65%, transparent 100%);
  mask-image: linear-gradient(to bottom, black 65%, transparent 100%);
  pointer-events: none;
}

.fh-card-snippet-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-size: var(--fh-text-3xl);
  opacity: 0.35;
}

.fh-card-text {
  font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: var(--fh-text-xs);
  line-height: var(--fh-leading-snug);
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--fh-text, #1e293b);
  background: transparent;
  border: none;
  padding: 0;
}

.fh-card-md h1, .fh-card-md h2, .fh-card-md h3, .fh-card-md h4, .fh-card-md h5, .fh-card-md h6 {
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-bold);
  margin: 0 0 0.2rem;
  line-height: var(--fh-leading-tight);
  color: var(--fh-text, #1e293b);
}

.fh-card-md p {
  margin: 0 0 0.25rem;
  font-size: var(--fh-text-xs);
}

.fh-card-md ul, .fh-card-md ol {
  margin: 0 0 0.25rem;
  padding-left: 1rem;
}

.fh-card-md li {
  font-size: var(--fh-text-xs);
  margin-bottom: 0.1rem;
}

.fh-card-md code {
  font-size: var(--fh-text-xs);
  background: rgba(0, 0, 0, 0.05);
  padding: 0.1rem 0.25rem;
  border-radius: 0.25rem;
}

.fh-card-md blockquote {
  margin: 0 0 0.25rem;
  padding-left: 0.5rem;
  border-left: 2px solid var(--fh-border, #cbd5e1);
  color: var(--fh-muted, #6b7280);
}

.fh-card-md .table-responsive {
  margin-bottom: 0.25rem;
}

/* Fallback state when image/video/pdf/text fails to load */
.fh-card-thumb .fh-card-thumb-fallback {
  display: none;
  margin-bottom: 0;
}

.fh-card-thumb.is-fallback {
  background: var(--fh-soft, #f8fafc);
}

.fh-card-thumb.is-fallback .fh-card-thumb-media,
.fh-card-thumb.is-fallback .fh-card-thumb-canvas,
.fh-card-thumb.is-fallback .fh-card-audio-cover,
.fh-card-thumb.is-fallback .fh-card-audio-play,
.fh-card-thumb.is-fallback .fh-card-snippet-content {
  display: none !important;
}

.fh-card-thumb.is-fallback .fh-card-thumb-fallback {
  display: flex !important;
}

@media (max-width: 575.98px) {
  .fh-card-thumb {
    /* The 4/3 ratio above already lands near the old 90px at phone card
       widths; only the trim and rhythm change here. */
    min-height: 4.5rem;
    border-radius: 0.55rem;
    margin-bottom: 0.5rem;
  }
}

/* Item actions: 3-dot (⋮) menu */
.fh-card-menu {
  position: absolute;
  top: 0.45rem;
  right: 0.45rem;
  z-index: 5;
}
/* No z-index change on open here (see the .fh-card comment above): the
   parent .fh-card already stops being a stacking context, so the fixed
   dropdown it contains escapes to the root and resolves at its own 1060. */
.fh-row-menu {
  display: inline-flex;
}
.fh-row-menu:has(.dropdown-menu.show),
.fh-row-menu:has([aria-expanded="true"]) {
  position: relative;
}
.fh-card-menu-toggle,
.fh-row-menu-toggle {
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  color: var(--fh-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-base);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  transition: background-color 0.15s, color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.fh-card-menu-toggle:hover,
.fh-card-menu-toggle:focus-visible,
.fh-card-menu-toggle.show,
.fh-row-menu-toggle:hover,
.fh-row-menu-toggle:focus-visible,
.fh-row-menu-toggle.show {
  background: #ffffff;
  color: var(--fh-text);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.14);
  outline: 0;
}
.fh-card-menu .dropdown-menu,
.fh-row-menu .dropdown-menu {
  min-width: 12rem;
  font-size: var(--fh-text-sm);
  right: auto !important;
  bottom: auto !important;
}
.fh-card-menu .dropdown-item i,
.fh-row-menu .dropdown-item i {
  width: 1rem;
  text-align: center;
}
.fh-card-menu form,
.fh-row-menu form {
  margin: 0;
}
.fh-card-menu form .dropdown-item,
.fh-row-menu form .dropdown-item {
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
}

.fh-empty {
  text-align: center;
  color: var(--fh-muted);
  padding: 2.75rem 1.5rem;
  background: #ffffff;
  border: 1.5px dashed var(--fh-border);
  border-radius: var(--fh-radius-xl, 0.85rem);
  font-size: var(--fh-text-base);
}
.fh-empty i {
  font-size: var(--fh-text-5xl);
  color: var(--fh-muted);
  display: block;
  margin-bottom: 0.75rem;
}

/* Dropzone — the visible drop band was removed; the real drag-active feedback
   is upload.js's full-page .fh-drag-overlay (styled separately below). */

/* Floating upload button (mockup) — fixed bottom-right, same trigger as the
   toolbar's "+ New" → File upload. Below the upload dock (1060) so an
   in-flight upload's status stays on top, and below the modal drawer's
   backdrop (1030 — see the z-index ladder above .fh-app) so a mobile/tablet
   user opening the sidebar can't still tap through to it. */
.fh-upload-fab {
  position: fixed;
  right: var(--fh-float-inset, 1.5rem);
  bottom: var(--fh-float-inset, 1.5rem);
  z-index: 1022;
  width: 3.25rem;
  height: 3.25rem;
  border: 0;
  border-radius: 50%;
  background: var(--fh-primary);
  color: #fff;
  font-size: var(--fh-text-xl);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 14px rgba(37, 99, 235, 0.35);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.fh-upload-fab:hover {
  background: var(--fh-primary-dark);
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(37, 99, 235, 0.4);
}
@media (max-width: 575.98px) {
  .fh-upload-fab {
    right: var(--fh-float-inset, 1rem);
    bottom: var(--fh-float-inset, 1rem);
    width: 2.9rem;
    height: 2.9rem;
  }
}

body:has(#upload-dock:not(.is-hidden)) .fh-upload-fab {
  opacity: 0;
  pointer-events: none;
}

/* ==========================================================================
   Google Drive Inspired Upload Progress Dock & Animations
   ========================================================================== */

/* Full Drag & Drop Overlay */
.fh-drag-overlay {
  position: fixed;
  inset: 0;
  z-index: 1055;
  background: rgba(248, 250, 252, 0.88);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.fh-drag-overlay.is-active {
  opacity: 1;
  pointer-events: auto;
}
.fh-drag-card {
  background: #ffffff;
  border: 2px dashed var(--fh-primary);
  border-radius: var(--fh-radius-lg, 0.75rem);
  padding: 2.5rem 3.5rem;
  text-align: center;
  box-shadow: 0 20px 40px rgba(37, 99, 235, 0.12);
  pointer-events: none;
  transform: scale(0.96);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.fh-drag-overlay.is-active .fh-drag-card {
  transform: scale(1);
}
.fh-drag-icon {
  font-size: var(--fh-text-6xl);
  color: var(--fh-primary);
  display: inline-block;
  animation: floatBounce 2s ease-in-out infinite;
}
.fh-drag-text {
  font-size: var(--fh-text-xl);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  margin-top: 1rem;
  margin-bottom: 0.25rem;
}
.fh-drag-subtext {
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
}

/* Floating Upload Progress Dock (Bottom Right) */
.fh-upload-dock {
  position: fixed;
  bottom: var(--fh-float-inset, 1.5rem);
  right: var(--fh-float-inset, 1.5rem);
  z-index: 1060;
  width: 370px;
  max-width: calc(100vw - 2rem);
  background: #ffffff;
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-lg, 0.75rem);
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.16), 0 2px 8px rgba(15, 23, 42, 0.08);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transform: translateY(0);
  opacity: 1;
  animation: uploadDockSlideUp 0.3s cubic-bezier(0.16, 1, 0.3, 1);
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.2s ease, box-shadow 0.2s ease;
}
.fh-upload-dock.is-hidden {
  display: none !important;
}

/* Dock Header */
.fh-upload-dock-header {
  background: var(--fh-ink, #14161a);
  color: #ffffff;
  padding: 0.65rem 0.9rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  user-select: none;
  cursor: pointer;
}
.fh-upload-dock-left {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex: 1;
  min-width: 0;
}
.fh-upload-dock-status-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  font-size: var(--fh-text-md);
  flex-shrink: 0;
}
.fh-upload-dock-status-icon .fa-spinner {
  color: #38bdf8;
}
.fh-upload-dock-status-icon .fa-circle-check {
  color: #4ade80;
  animation: checkmarkPop 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.fh-upload-dock-status-icon .fa-circle-exclamation {
  color: #f87171;
}
.fh-upload-dock-title {
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-tight);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #f8fafc;
}
.fh-upload-dock-actions {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  flex-shrink: 0;
}
.fh-upload-dock-btn {
  background: transparent;
  border: 0;
  color: var(--fh-muted);
  padding: 4px 6px;
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-xs);
  cursor: pointer;
  line-height: var(--fh-leading-none);
  transition: color 0.15s, background 0.15s;
}
.fh-upload-dock-btn:hover {
  color: #ffffff;
  background: rgba(255, 255, 255, 0.12);
}

/* Overall Progress Strip directly under header */
.fh-upload-dock-bar {
  height: 3px;
  background: rgba(255, 255, 255, 0.15);
  width: 100%;
  position: relative;
  overflow: hidden;
}
.fh-upload-dock-bar-fill {
  height: 100%;
  width: 0%;
  background: #38bdf8;
  transition: width 0.22s ease-out;
}
.fh-upload-dock-bar.is-complete .fh-upload-dock-bar-fill {
  background: #4ade80;
}

/* Dock Item List */
.fh-upload-dock-body {
  max-height: 240px;
  overflow-y: auto;
  background: #ffffff;
  overscroll-behavior: contain;
  transition: max-height 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.2s ease;
}
.fh-upload-dock-body::-webkit-scrollbar {
  width: 5px;
}
.fh-upload-dock-body::-webkit-scrollbar-track {
  background: #f8fafc;
}
.fh-upload-dock-body::-webkit-scrollbar-thumb {
  background: #cbd5e1;
  border-radius: 3px;
}
.fh-upload-dock-body::-webkit-scrollbar-thumb:hover {
  background: #94a3b8;
}

/* Dock Item Row */
.fh-upload-item {
  display: flex;
  align-items: center;
  padding: 0.55rem 0.85rem;
  gap: 0.65rem;
  border-bottom: 1px solid #f1f5f9;
  position: relative;
  transition: background 0.15s;
}
.fh-upload-item:last-child {
  border-bottom: 0;
}
.fh-upload-item:hover {
  background: #f8fafc;
}
.fh-upload-item-icon {
  width: 30px;
  height: 30px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-base);
  flex-shrink: 0;
  background: #f1f5f9;
  color: var(--fh-muted);
}
/* Per-type tinted palette lives with .fh-card-icon's own rules (Browse Cards
   section above) — one declaration per type shared by both surfaces. */

.fh-upload-item-details {
  flex: 1;
  min-width: 0;
}
.fh-upload-item-name {
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-medium);
  color: var(--fh-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: var(--fh-leading-tight);
}
.fh-upload-item-meta {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
  margin-top: 1px;
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
.fh-upload-item-progress-track {
  margin-top: 4px;
  height: 3px;
  border-radius: 2px;
  background: #e2e8f0;
  overflow: hidden;
  width: 100%;
}
.fh-upload-item-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--fh-primary);
  border-radius: 2px;
  transition: width 0.2s ease-out;
}
.fh-upload-item-status {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
}
.fh-upload-item-status .fa-circle-check {
  color: #16a34a;
  font-size: var(--fh-text-lg);
  animation: checkmarkPop 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.fh-upload-item-status .fa-circle-exclamation {
  color: #dc2626;
  font-size: var(--fh-text-lg);
}
.fh-upload-item-cancel {
  border: 0;
  background: transparent;
  color: var(--fh-muted);
  cursor: pointer;
  padding: 3px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-xs);
  transition: color 0.15s, background 0.15s;
}
.fh-upload-item-cancel:hover {
  color: var(--fh-danger);
  background: #fee2e2;
}

/* Minimized Dock State */
.fh-upload-dock.is-minimized {
  box-shadow: 0 4px 16px rgba(15, 23, 42, 0.12);
}
.fh-upload-dock.is-minimized .fh-upload-dock-body {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
}

/* Conflict Dialog (Upload / New-Folder) — Windows "Replace or skip files"
   layout: stacked action rows instead of a button strip, since each row is a
   whole resolution (Overwrite / Keep both / Skip / Open existing). */
.fh-conflict-message {
  color: var(--fh-text);
  margin-bottom: 1rem;
}
.fh-conflict-actions {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.fh-conflict-row {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  width: 100%;
  padding: 0.65rem 0.75rem;
  background: transparent;
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius, 0.5rem);
  text-align: left;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.fh-conflict-row:hover,
.fh-conflict-row:focus-visible {
  background: #f1f5f9;
  border-color: var(--fh-primary);
  outline: none;
}
.fh-conflict-row-icon {
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #eef2ff;
  color: var(--fh-primary);
  font-size: var(--fh-text-base);
}
.fh-conflict-row-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}
.fh-conflict-row-title {
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  font-size: var(--fh-text-md);
}
.fh-conflict-row-sub {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
}
.fh-conflict-apply-all {
  margin-top: 0.85rem;
  padding-left: 1.5rem;
}
.fh-conflict-apply-all .form-check-label {
  font-size: var(--fh-text-base);
  color: var(--fh-muted);
}

/* Success Highlight Animation on Newly Uploaded Grid Cards and Table Rows */
.fh-card.is-newly-uploaded,
.fh-list-card table.table-hover > tbody > tr.is-newly-uploaded > * {
  animation: uploadSuccessFlash 2.8s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

/* Keyframes */
@keyframes uploadDockSlideUp {
  0% {
    transform: translateY(24px) scale(0.96);
    opacity: 0;
  }
  100% {
    transform: translateY(0) scale(1);
    opacity: 1;
  }
}

@keyframes checkmarkPop {
  0% {
    transform: scale(0.5);
    opacity: 0;
  }
  65% {
    transform: scale(1.2);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes floatBounce {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-6px);
  }
}

@keyframes uploadSuccessFlash {
  0% {
    background-color: rgba(37, 99, 235, 0.2);
    box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.35);
    transform: translateY(-2px);
  }
  25% {
    background-color: rgba(37, 99, 235, 0.12);
    box-shadow: 0 0 0 1.5px rgba(37, 99, 235, 0.2);
    transform: translateY(0);
  }
  100% {
    background-color: transparent;
    box-shadow: none;
    transform: translateY(0);
  }
}

/* List: Hero Content Stage */
.fh-list-card {
  background: #ffffff;
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-xl, 0.85rem);
  margin-inline: var(--fh-head-inset, 0.25rem);
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.03);
}
.fh-list-card:has(.dropdown-menu.show),
.fh-list-card.has-open-menu {
  overflow: visible !important;
}
.fh-list-card:has(.dropdown-menu.show) .table-responsive,
.fh-list-card.has-open-menu .table-responsive {
  overflow: visible !important;
}
.fh-list-card .table {
  margin-bottom: 0;
  font-size: var(--fh-text-sm);
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
}
.fh-list-card .table thead th {
  border-bottom: 1px solid var(--fh-border);
  border-top: none;
  color: var(--fh-muted);
  font-weight: var(--fh-weight-semibold);
  font-size: var(--fh-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  background: var(--fh-soft);
  padding: var(--fh-row-pad-y, 0.75rem) var(--fh-row-pad-x, 1rem);
  vertical-align: middle;
}
/* Click-to-select rows — same is-selected language as the grid cards. */
#list-view tbody tr[data-id] {
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: background-color 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
/* Give the active row's menu a containing block without a stacking context
   (see the .fh-card comment above) so its fixed dropdown escapes to the
   root and resolves at its own 1060 instead of being capped here. */
#list-view tbody tr:has(.dropdown-menu.show),
#list-view tbody tr:has([aria-expanded="true"]),
#list-view tbody tr.has-open-menu {
  position: relative;
}
#list-view tbody tr:has(.dropdown-menu.show) > td,
#list-view tbody tr:has([aria-expanded="true"]) > td,
#list-view tbody tr.has-open-menu > td {
  position: relative;
}
#list-view tbody td {
  padding: var(--fh-row-pad-y, 0.75rem) var(--fh-row-pad-x, 1rem);
  vertical-align: middle;
  border-bottom: 1px solid var(--fh-border);
  color: var(--fh-text);
  transition: background-color 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
#list-view tbody tr:last-child td {
  border-bottom: none;
}
#list-view tbody td.text-center {
  font-size: var(--fh-text-xl);
}
#list-view tbody td.text-center i.fa-folder {
  color: #f59e0b;
}
#list-view tbody a.js-item-link {
  font-weight: var(--fh-weight-medium);
  color: var(--fh-text);
  text-decoration: none;
  transition: color 0.15s ease;
}
#list-view tbody a.js-item-link:hover {
  color: var(--fh-primary);
}
.fh-list-card table.table-hover > tbody > tr:hover > * {
  background-color: var(--fh-primary-soft, #eff6ff);
}
.fh-list-card table.table-hover > tbody > tr.is-selected > * {
  background-color: var(--fh-selected-bg, #f0f7ff) !important;
  color: var(--fh-primary);
}
.fh-list-card table.table-hover > tbody > tr.is-selected td:first-child {
  box-shadow: inset 3px 0 0 var(--fh-primary);
}
.fh-list-card table.table-hover > tbody > tr.is-selected:hover > * {
  background-color: var(--fh-selected-bg-hover, #e0effe) !important;
  color: var(--fh-primary-dark);
}

/* List-view column widths — named tokens instead of per-cell inline styles,
   shared by the header row (_ContentPanel.cshtml) and every body row
   (_BrowseItems.cshtml) so the two stay pixel-aligned from one place. */
/* Widths are in rem, not px, so they track the root type ramp — at 2560px+
   the text grows but px columns would not have, squeezing the very content
   they were sized around. */
.fh-col-icon { width: 1.875rem; }
.fh-col-kind { width: 2.5rem; }
.fh-col-size { width: 6.25rem; }
.fh-col-modified { width: 10rem; }
.fh-col-uploader { width: 8.75rem; }
.fh-col-uploader-name { max-width: 8.125rem; }
.fh-col-actions { width: 7.5rem; }
/* Admin All Files (Views/AdminFileExplorer) only — the row-select checkbox
   column is wider than .fh-col-icon (1.875rem) so the checkbox sits
   comfortably. (There used to be a .fh-col-owner here too, but Owner /
   Department was one value per folder, not per row — it now reads once in
   .admin-files-owner, in the pane header, instead of on every row.) */
.fh-col-select { width: 2.5rem; }

/* These five fixed columns total roughly 27rem before the fluid Name column
   gets any width at all. Inside .table-responsive that scrolls rather than
   breaking the page, but on a phone it meant the Name column — the only one
   anybody scans — was pushed almost entirely out of view behind a horizontal
   scroll. Retiring the secondary columns at narrow widths gives Name the
   space instead; none of the dropped data is lost, since the row's "⋮" →
   Details panel shows uploader and modified date in full. */
@media (max-width: 767.98px) {
  .fh-col-uploader,
  .fh-col-modified { display: none; }
}
@media (max-width: 575.98px) {
  .fh-col-size { display: none; }
  .fh-col-actions { width: 3rem; }
}

/* Status bar */
.fh-statusbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
  background: #fff;
  border: 1px solid var(--fh-border);
  border-radius: 0.75rem;
  padding: 0.5rem 0.75rem;
}
.fh-statusbar strong {
  color: var(--fh-muted);
  font-weight: var(--fh-weight-semibold);
}

/* Selection toolbar: Floating action feedback.

   Deliberately taken OUT of .fh-content's flex flow (position: fixed) rather
   than rendered as a normal block between the toolbar and the grid. In flow it
   appeared on the first click of a double-click and pushed the grid/list down
   by its own height + the .fh-content gap — the second click then landed on
   whatever slid into that spot, so double-click-to-open was unreliable. As a
   fixed overlay it can appear and disappear without moving a single item. */
.fh-selection-toolbar {
  position: fixed;
  left: 50%;
  bottom: calc(var(--fh-float-inset, 1.5rem) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 1025; /* above the content, below the modal drawer's backdrop
                    (1030) so an open sidebar covers it too — see the
                    z-index ladder above .fh-app */
  max-width: calc(100vw - 2rem);
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 999px;
  padding: 0.5rem 0.85rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  box-shadow: 0 10px 30px -6px rgba(15, 23, 42, 0.22), 0 2px 8px rgba(37, 99, 235, 0.12);
  animation: fh-selection-toolbar-in 0.15s ease-out;
}
@keyframes fh-selection-toolbar-in {
  from { opacity: 0; transform: translate(-50%, 0.5rem); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .fh-selection-toolbar { animation: none; }
}
/* Narrow screens: stretch edge-to-edge instead of centering, and let the
   buttons wrap rather than overflow the viewport. */
@media (max-width: 575.98px) {
  .fh-selection-toolbar {
    left: 0.75rem;
    right: 0.75rem;
    transform: none;
    max-width: none;
    border-radius: 0.75rem;
    flex-wrap: wrap;
    justify-content: center;
  }
  @keyframes fh-selection-toolbar-in {
    from { opacity: 0; transform: translateY(0.5rem); }
    to   { opacity: 1; transform: translateY(0); }
  }
}
/* While the floating bar is up, extend the panel's tail so it can't sit on top
   of the last row / feed status. Padding at the very END of the flow grows the
   page downward without moving anything already rendered above it. */
.fh-panel:has(> .fh-selection-toolbar:not(.d-none)) {
  padding-bottom: calc(4.5rem + env(safe-area-inset-bottom, 0px));
}

/* Both the floating upload button and the selection toolbar are pinned to the
   bottom of the viewport. While a selection is active the FAB steps up above
   the toolbar; when the upload dock is visible the FAB stands down entirely
   (see body:has(#upload-dock:not(.is-hidden)) .fh-upload-fab above).
   z-index: FAB 1022, selection toolbar 1025. */
.fh-panel:has(> .fh-selection-toolbar:not(.d-none)) > .fh-upload-fab {
  bottom: calc(5.5rem + env(safe-area-inset-bottom, 0px));
}

@media (max-width: 991.98px) {
  .fh-panel:has(> .fh-selection-toolbar:not(.d-none)) > .fh-upload-fab {
    bottom: calc(6.5rem + env(safe-area-inset-bottom, 0px));
  }
}
@media (prefers-reduced-motion: no-preference) {
  .fh-upload-fab {
    transition: transform 0.15s ease, box-shadow 0.15s ease,
                background 0.15s ease, bottom 0.15s ease;
  }
}
#selection-count {
  font-weight: var(--fh-weight-semibold);
  color: #1e40af !important;
  font-size: var(--fh-text-sm);
}

/* ==========================================================================
   App-wide modernization layer — restyles the remaining default
   Bootstrap 5 components (forms, buttons, cards, tables, modals,
   dropdowns, badges, pagination, navs, alerts) so every screen matches the
   `fh-*` visual language above, not just the Browse overview.

   Approach: first re-point the Bootstrap CSS custom properties (radius,
   shadow, semantic colors) at the `--fh-*` tokens so any component that
   already reads them (cards, modals, alerts, badges, pagination radius,
   dropdowns…) picks up the new look for free. Anything Bootstrap
   hardcodes as a literal hex value (e.g. `.btn-primary`, `.page-link.active`,
   old Bootstrap-4-style `.badge-success`/`.close`) gets a small explicit
   override below that.
   ========================================================================== */
:root {
  /* Additional shared tokens, extending the fh-* palette above */
  --fh-radius-sm: 0.375rem;
  --fh-radius: 0.5rem;
  --fh-radius-lg: 0.75rem;
  --fh-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
  --fh-shadow: 0 10px 25px rgba(15, 23, 42, 0.08);
  --fh-success: #16a34a;
  --fh-success-rgb: 22, 163, 74;
  --fh-danger: #dc2626;
  --fh-danger-rgb: 220, 38, 38;
  --fh-warning: #d97706;
  --fh-warning-rgb: 217, 119, 6;
  --fh-info: #0891b2;
  --fh-info-rgb: 8, 145, 178;
  --fh-secondary: var(--fh-muted);
  --fh-secondary-rgb: 100, 116, 139;
  /* Soft/tinted variants — hover and selected states across tree pickers,
     list rows, and panels, so those states read from tokens instead of
     one-off hex values. */
  --fh-primary-soft: #eff6ff;
  --fh-primary-soft-border: #bfdbfe;
  --fh-hover: #f1f5f9;
  --fh-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.15);
  --fh-transition-fast: 0.15s ease;

  /* Bootstrap variable overrides — cascade into every component below */
  --bs-border-radius-sm: var(--fh-radius-sm);
  --bs-border-radius: var(--fh-radius);
  --bs-border-radius-lg: var(--fh-radius-lg);
  --bs-border-radius-xl: 1rem;
  --bs-border-radius-2xl: 1.25rem;
  --bs-border-radius-pill: 50rem;
  --bs-box-shadow: var(--fh-shadow);
  --bs-box-shadow-sm: var(--fh-shadow-sm);
  --bs-body-color: var(--fh-text);
  --bs-border-color: var(--fh-border);
  --bs-secondary-color: var(--fh-muted);
  --bs-link-color: var(--fh-primary);
  --bs-link-color-rgb: 37, 99, 235;
  --bs-link-hover-color: var(--fh-primary-dark);
  --bs-link-hover-color-rgb: 29, 78, 216;
  --bs-primary: var(--fh-primary);
  --bs-primary-rgb: 37, 99, 235;
  --bs-secondary: var(--fh-secondary);
  --bs-secondary-rgb: var(--fh-secondary-rgb);
  --bs-success: var(--fh-success);
  --bs-success-rgb: var(--fh-success-rgb);
  --bs-danger: var(--fh-danger);
  --bs-danger-rgb: var(--fh-danger-rgb);
  --bs-warning: var(--fh-warning);
  --bs-warning-rgb: var(--fh-warning-rgb);
  --bs-info: var(--fh-info);
  --bs-info-rgb: var(--fh-info-rgb);
}

/* ==========================================================================
   Admin All Files explorer (Views/AdminFileExplorer) — full-height two-pane
   file manager. Tree + listing fill the remaining viewport under the navbar
   (one scroller per pane), not a 68vh card in a padded article. Footer is
   omitted for FileExplorer in _Layout.cshtml the same way Browse is.

   Everything here is scoped under .admin-files-* or body.fh-admin-files so it
   can't leak onto /drive or other admin pages, which share .fh-list-card,
   .fh-empty, .fh-selection-toolbar and the .fh-col-* family with this page.
   ========================================================================== */

/* Page chrome: size the explorer to the leftover viewport and drop the
   global well padding / --fh-shell-max cap. Overflow stays visible on the
   chrome (html/body/main/content) so Popper strategy:fixed "+ New" / row
   menus are not clipped; the shell is the only overflow:hidden box, and
   its :has(.dropdown-menu.show) rule lifts that while a menu is open.
   Document double-scroll is prevented by a definite remaining-viewport
   height on the shell plus min-height:0 on .fh-main (the global
   min-height: calc(100vh - header) is taller than dvh on mobile). */
html:has(body.fh-admin-files) {
  height: 100%;
  height: 100vh;
  height: 100dvh;
}
body.fh-admin-files {
  --admin-files-well-pad: 0.5rem;
  height: 100%;
  overscroll-behavior: none;
}
@media (max-width: 767.98px) {
  body.fh-admin-files { --admin-files-well-pad: 0px; }
}

body.fh-admin-files .fh-shell {
  height: 100%;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* Override .fh-main's global min-height (100vh - header): on mobile vh is
   taller than dvh, and that min-height is what grew the document under the
   explorer. */
body.fh-admin-files .fh-main {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
body.fh-admin-files .fh-content {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: var(--admin-files-well-pad) 0;
}
body.fh-admin-files .fh-content > .container-fluid {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  max-width: none;
  width: 100%;
  padding: 0 var(--admin-files-well-pad);
  display: flex;
  flex-direction: column;
}

.admin-files-shell {
  display: grid;
  grid-template-columns: 20rem minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  /* Remaining viewport after the fixed navbar and this page's well padding.
     dvh includes mobile browser chrome; vh is the fallback. Footer is not
     in the tree (hidden in _Layout), so it is not subtracted. max-height:
     100% caps 1px rounding so the document does not grow a second bar. */
  height: calc(100vh - var(--fh-header-h) - (2 * var(--admin-files-well-pad)));
  height: calc(100dvh - var(--fh-header-h) - (2 * var(--admin-files-well-pad)));
  max-height: 100%;
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-lg);
  background: #fff;
  overflow: hidden;
}
@media (min-width: 1920px) {
  .admin-files-shell {
    grid-template-columns: 24rem minmax(0, 1fr);
  }
}

/* Both panes scroll independently inside the shell instead of growing the
   page. min-height:0 is what lets a grid/flex child shrink below its content
   so overflow-y:auto actually fires. Row menus escape via strategy:fixed on
   every .fh-row-menu-toggle / [data-fh-menu]. */
.admin-files-tree,
.admin-files-listing {
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.admin-files-tree {
  border-right: 1px solid var(--fh-border);
  padding: 1rem;
}
.admin-files-listing {
  display: flex;
  flex-direction: column;
}
/* Empty state ("Select a folder…" / "This folder is empty.") fills the
   listing pane rather than sitting as a short dashed card at the top. */
.admin-files-listing > .fh-empty {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}
/* Same 6px scrollbar treatment as .fh-tree-picker (this file, ~line 141). */
.admin-files-tree::-webkit-scrollbar,
.admin-files-listing::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
.admin-files-tree::-webkit-scrollbar-thumb,
.admin-files-listing::-webkit-scrollbar-thumb {
  background-color: #cbd5e1;
  border-radius: 3px;
}
.admin-files-tree::-webkit-scrollbar-thumb:hover,
.admin-files-listing::-webkit-scrollbar-thumb:hover {
  background-color: var(--fh-muted);
}
.admin-files-tree::-webkit-scrollbar-track,
.admin-files-listing::-webkit-scrollbar-track {
  background: transparent;
}

/* Pane header (breadcrumb + count/owner + "+ New") pinned while the listing
   scrolls inside its own container — same rhythm tokens as .fh-content-head
   (--fh-head-pad-y / --fh-head-gap), pane-scoped rather than viewport-scoped
   since this sticks to the top of the PANE, not the page. Horizontal padding
   is 1rem to line up with .fh-list-card's own cell padding once its border
   is flattened away below. */
.admin-files-head {
  position: sticky;
  top: 0;
  z-index: 2;
  flex-shrink: 0;
  background: #fff;
  border-bottom: 1px solid var(--fh-border);
  padding: var(--fh-head-pad-y) 1rem;
  display: flex;
  flex-direction: column;
  gap: var(--fh-head-gap);
  overflow: visible;
}
.admin-files-head .fh-breadcrumb {
  margin: 0;
}
.admin-files-head-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: 0.75rem 1rem;
  min-width: 0;
}
.admin-files-head-main > :first-child {
  min-width: 0;
}
.admin-files-head .fh-toolbar {
  flex-shrink: 0;
}
/* Owner / Department, stated once per folder instead of once per row — the
   table's Owner column was retired because Model.OwnerLabel is one value for
   the whole folder, not per-row data (every row rendered the same string). */
.admin-files-owner {
  padding: 0.15rem 0.6rem;
  background: var(--fh-soft);
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-sm);
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
  font-weight: var(--fh-weight-medium);
}

/* Flatten .fh-list-card inside the listing pane so it reads as the pane's
   own surface rather than a card nested inside the shell's card. Its
   :has(.dropdown-menu.show) overflow: visible rules are untouched — they
   belong to .fh-list-card itself and are not redefined here. */
.admin-files-listing .fh-list-card {
  border: 0;
  border-radius: 0;
  box-shadow: none;
  margin: 0;
  margin-inline: 0;
}
.admin-files-listing .table {
  width: 100%;
}

/* While a dropdown is open, lift overflow clips on the shell and listing pane
   so Popper strategy:fixed menus escape the scroll container (same problem
   /drive solved with #list-view rules — admin table is not inside that id). */
.admin-files-shell:has(.dropdown-menu.show),
.admin-files-shell:has(.has-open-menu),
.admin-files-shell:has([aria-expanded="true"]) {
  overflow: visible;
}
.admin-files-listing:has(.dropdown-menu.show),
.admin-files-listing:has(.has-open-menu),
.admin-files-listing:has([aria-expanded="true"]) {
  overflow-y: visible;
}

/* Open row — mirrors #list-view tbody tr treatment for row "⋮" menus. */
.admin-files-listing tbody tr:has(.dropdown-menu.show),
.admin-files-listing tbody tr:has([aria-expanded="true"]),
.admin-files-listing tbody tr.has-open-menu {
  position: relative;
}
.admin-files-listing tbody tr:has(.dropdown-menu.show) > td,
.admin-files-listing tbody tr:has([aria-expanded="true"]) > td,
.admin-files-listing tbody tr.has-open-menu > td {
  position: relative;
}

/* While the floating selection bar is up, give the pane's own scroll
   container the same tail padding .fh-content gets on /drive (this file,
   ~line 2855) — that rule only matches .fh-content's direct child, so it
   never fires here on its own. Safe-area keeps the bar above the
   home-indicator on a phone. */
.admin-files-shell:has(.fh-selection-toolbar:not(.d-none)) .admin-files-listing {
  padding-bottom: calc(4.5rem + env(safe-area-inset-bottom, 0px));
}
.admin-files-listing .fh-selection-toolbar {
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
}
@media (max-width: 575.98px) {
  .admin-files-listing .fh-selection-toolbar {
    bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));
  }
}

@media (max-width: 1023.98px) {
  /* Phone + tablet: one column. Landing = tree; .is-browsing (set by
     admin-files.js after a listing load) = listing only. Do not park a
     16rem tree beside a squeezed listing. The "All files" crumb is a real
     <a href="/Admin/Files"> that leaves browsing mode. */
  .admin-files-shell {
    grid-template-columns: minmax(0, 1fr);
  }
  .admin-files-shell:not(.is-browsing) .admin-files-listing {
    display: none;
  }
  .admin-files-shell.is-browsing .admin-files-tree {
    display: none;
  }
  /* Checkbox column leaves less room for Name — hide secondary columns earlier
     than /drive's 767px breakpoint (scoped here so browse is untouched). */
  .admin-files-listing .fh-col-uploader,
  .admin-files-listing .fh-col-modified {
    display: none;
  }
}

@media (max-width: 767.98px) {
  .admin-files-shell {
    border-radius: 0;
    border-left: 0;
    border-right: 0;
    border-bottom: 0;
  }
  .admin-files-tree {
    border-right: 0;
  }
}

/* --- Buttons -------------------------------------------------------------
   Bootstrap bakes each variant's colors into literal `--bs-btn-*` hex values
   rather than reading `--bs-primary`, so the brand/semantic variants need an
   explicit repoint. Structural bits (radius, focus ring, transitions) are
   shared across all variants. */
.btn {
  border-radius: var(--fh-radius);
  font-weight: var(--fh-weight-medium);
  transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s, color 0.15s;
}
.btn-sm { border-radius: var(--fh-radius-sm); }
.btn-lg { border-radius: var(--fh-radius); }
.btn:disabled, .btn.disabled { opacity: 0.55; box-shadow: none; }

.btn-primary {
  --bs-btn-bg: var(--fh-primary);
  --bs-btn-border-color: var(--fh-primary);
  --bs-btn-hover-bg: var(--fh-primary-dark);
  --bs-btn-hover-border-color: var(--fh-primary-dark);
  --bs-btn-active-bg: var(--fh-primary-dark);
  --bs-btn-active-border-color: var(--fh-primary-dark);
  --bs-btn-disabled-bg: var(--fh-primary);
  --bs-btn-disabled-border-color: var(--fh-primary);
}
.btn-outline-primary {
  --bs-btn-color: var(--fh-primary);
  --bs-btn-border-color: var(--fh-primary);
  --bs-btn-hover-bg: var(--fh-primary);
  --bs-btn-hover-border-color: var(--fh-primary);
  --bs-btn-active-bg: var(--fh-primary);
  --bs-btn-active-border-color: var(--fh-primary);
  --bs-btn-disabled-color: var(--fh-primary);
  --bs-btn-disabled-border-color: var(--fh-primary);
}
.btn-secondary {
  --bs-btn-bg: var(--fh-secondary);
  --bs-btn-border-color: var(--fh-secondary);
  --bs-btn-hover-bg: #4b5b73;
  --bs-btn-hover-border-color: #4b5b73;
  --bs-btn-active-bg: #4b5b73;
  --bs-btn-active-border-color: #4b5b73;
}
.btn-outline-secondary {
  --bs-btn-color: var(--fh-secondary);
  --bs-btn-border-color: var(--fh-border);
  --bs-btn-hover-bg: var(--fh-soft);
  --bs-btn-hover-border-color: var(--fh-border);
  --bs-btn-hover-color: var(--fh-text);
  --bs-btn-active-bg: var(--fh-soft);
  --bs-btn-active-border-color: var(--fh-border);
  --bs-btn-active-color: var(--fh-text);
}
/* Solid and outline variants must NOT share `--bs-btn-bg`/`--bs-btn-color`:
   a shared selector left `--bs-btn-bg` set to the brand color on the
   outline button too, so its (also brand-colored) text/icon sat on a
   same-color fill — invisible until `:hover` swapped the text to white.
   Each variant gets its own block instead, mirroring the already-correct
   `.btn-outline-primary`/`.btn-outline-secondary` pattern above. */
.btn-success {
  --bs-btn-bg: var(--fh-success);
  --bs-btn-border-color: var(--fh-success);
  --bs-btn-color: #fff;
  --bs-btn-hover-bg: #15803d;
  --bs-btn-hover-border-color: #15803d;
  --bs-btn-active-bg: #15803d;
  --bs-btn-active-border-color: #15803d;
}
.btn-outline-success {
  --bs-btn-color: var(--fh-success);
  --bs-btn-border-color: var(--fh-success);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--fh-success);
  --bs-btn-hover-border-color: var(--fh-success);
  --bs-btn-active-bg: var(--fh-success);
  --bs-btn-active-border-color: var(--fh-success);
  --bs-btn-disabled-color: var(--fh-success);
  --bs-btn-disabled-border-color: var(--fh-success);
}
.btn-danger {
  --bs-btn-bg: var(--fh-danger);
  --bs-btn-border-color: var(--fh-danger);
  --bs-btn-color: #fff;
  --bs-btn-hover-bg: #b91c1c;
  --bs-btn-hover-border-color: #b91c1c;
  --bs-btn-active-bg: #b91c1c;
  --bs-btn-active-border-color: #b91c1c;
}
.btn-outline-danger {
  --bs-btn-color: var(--fh-danger);
  --bs-btn-border-color: var(--fh-danger);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--fh-danger);
  --bs-btn-hover-border-color: var(--fh-danger);
  --bs-btn-active-bg: var(--fh-danger);
  --bs-btn-active-border-color: var(--fh-danger);
  --bs-btn-disabled-color: var(--fh-danger);
  --bs-btn-disabled-border-color: var(--fh-danger);
}
.btn-warning {
  --bs-btn-bg: var(--fh-warning);
  --bs-btn-border-color: var(--fh-warning);
  --bs-btn-color: #fff;
  --bs-btn-hover-bg: #b45309;
  --bs-btn-hover-border-color: #b45309;
  --bs-btn-active-bg: #b45309;
  --bs-btn-active-border-color: #b45309;
}
.btn-outline-warning {
  --bs-btn-color: var(--fh-warning);
  --bs-btn-border-color: var(--fh-warning);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--fh-warning);
  --bs-btn-hover-border-color: var(--fh-warning);
  --bs-btn-active-bg: var(--fh-warning);
  --bs-btn-active-border-color: var(--fh-warning);
  --bs-btn-disabled-color: var(--fh-warning);
  --bs-btn-disabled-border-color: var(--fh-warning);
}
.btn-info {
  --bs-btn-bg: var(--fh-info);
  --bs-btn-border-color: var(--fh-info);
  --bs-btn-color: #fff;
  --bs-btn-hover-bg: #0e7490;
  --bs-btn-hover-border-color: #0e7490;
  --bs-btn-active-bg: #0e7490;
  --bs-btn-active-border-color: #0e7490;
}
.btn-outline-info {
  --bs-btn-color: var(--fh-info);
  --bs-btn-border-color: var(--fh-info);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--fh-info);
  --bs-btn-hover-border-color: var(--fh-info);
  --bs-btn-active-bg: var(--fh-info);
  --bs-btn-active-border-color: var(--fh-info);
  --bs-btn-disabled-color: var(--fh-info);
  --bs-btn-disabled-border-color: var(--fh-info);
}

.btn-group > .btn, .btn-group-sm > .btn { box-shadow: none; }

/* --- Forms ----------------------------------------------------------------
   Login/admin forms still use the raw `.form-control`/`.form-group` markup
   from before the FileHub refactor. Inputs/selects/textareas get the same
   soft-tinted-surface treatment as the rest of the fh-* UI: a muted fill at
   rest (instead of stark white on a hard grey border) that lifts to white
   with a tasteful ring on focus, so they read as one connected system with
   the search box, dropzone, and toolbar rather than bare Bootstrap defaults. */
.form-label, label { font-size: var(--fh-text-base); font-weight: var(--fh-weight-medium); color: var(--fh-text); }
.form-control, .form-select {
  background-color: var(--fh-soft);
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius);
  font-size: var(--fh-text-base);
  color: var(--fh-text);
  padding: 0.5rem 0.75rem;
  box-shadow: none;
  transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.form-control::placeholder { color: var(--fh-muted); }
.form-control:hover:not(:disabled):not([readonly]):not(:focus),
.form-select:hover:not(:disabled):not(:focus) {
  border-color: #cbd5e1;
}
.form-control:focus, .form-select:focus {
  background-color: #fff;
  border-color: var(--fh-primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}
.form-control:disabled, .form-control[readonly], .form-select:disabled {
  background-color: var(--fh-soft);
  color: var(--fh-muted);
  border-color: var(--fh-border);
  opacity: 1;
}
.form-control.is-invalid, .form-select.is-invalid,
.form-control.is-invalid:focus, .form-select.is-invalid:focus {
  border-color: var(--fh-danger);
  box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12);
}
.form-control.is-valid, .form-select.is-valid,
.form-control.is-valid:focus, .form-select.is-valid:focus {
  border-color: var(--fh-success);
}
.form-control.is-valid:focus, .form-select.is-valid:focus {
  box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.12);
}
textarea.form-control { min-height: 5.5rem; line-height: var(--fh-leading-normal); resize: vertical; }
.form-text { font-size: var(--fh-text-xs); color: var(--fh-muted); margin-top: 0.3rem; }
.invalid-feedback { font-size: var(--fh-text-xs); color: var(--fh-danger); }
.valid-feedback { font-size: var(--fh-text-xs); color: var(--fh-success); }

/* Autofilled inputs (browser password managers, saved credentials on the
   login form) paint their own yellow/blue background over ours — repaint it
   back to the fh surface via the long-transition trick, and keep our text
   color so contrast/readability doesn't regress. */
.form-control:-webkit-autofill,
.form-control:-webkit-autofill:hover,
.form-control:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--fh-text);
  -webkit-box-shadow: 0 0 0 1000px var(--fh-soft) inset;
  box-shadow: 0 0 0 1000px var(--fh-soft) inset;
  transition: background-color 9999s ease-in-out 0s;
}

/* Input groups (e.g. the "temporary password" copy field) — Bootstrap 5
   only auto-joins direct-child `.form-control`/`.btn` siblings; the app's
   BS4-style `.input-group-append` wrapper divs need the join rules
   reapplied manually so the seam matches the rest of the fh-* surfaces. */
.input-group > .form-control { background-color: var(--fh-soft); }
.input-group-prepend, .input-group-append { display: flex; }
.input-group-text {
  background-color: var(--fh-soft);
  border: 1px solid var(--fh-border);
  color: var(--fh-muted);
  font-size: var(--fh-text-base);
}
.input-group > .input-group-prepend > .btn,
.input-group > .input-group-prepend > .input-group-text,
.input-group > .input-group-append > .btn,
.input-group > .input-group-append > .input-group-text {
  border-radius: var(--fh-radius);
}
.input-group > .form-control:not(:last-child),
.input-group > .input-group-prepend + .form-control {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.input-group > .input-group-append > .btn,
.input-group > .input-group-append > .input-group-text {
  margin-left: -1px;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
.input-group > .input-group-prepend > .btn,
.input-group > .input-group-prepend > .input-group-text {
  margin-right: -1px;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
/* Tag Helper validation spans render as `.text-danger` next to each field
   rather than Bootstrap's `.invalid-feedback`, so match the same small,
   breathing-room treatment. */
.form-group .text-danger, .form-group + .text-danger,
form .text-danger:not(.btn):not(.dropdown-item) {
  display: block;
  font-size: var(--fh-text-xs);
  margin-top: 0.25rem;
}
div[asp-validation-summary] ul, .validation-summary-errors ul { margin: 0; padding-left: 1.1rem; }
.form-group { margin-bottom: 1rem; }
.form-check-input {
  border-color: #cbd5e1;
  border-radius: 0.3rem;
}
.form-check-input[type="radio"] { border-radius: 50%; }
.form-check-input:checked {
  background-color: var(--fh-primary);
  border-color: var(--fh-primary);
}
.form-check-input:focus {
  border-color: var(--fh-primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}
.form-check-label { font-size: var(--fh-text-base); color: var(--fh-text); }
/* An iCheck-style checkbox wrapper still used on the login form — no
   iCheck plugin is bundled, so style the native checkbox directly. */
.icheck-primary input[type="checkbox"], .icheck-primary input[type="radio"] {
  accent-color: var(--fh-primary);
  width: 1.05rem;
  height: 1.05rem;
  vertical-align: middle;
  margin-right: 0.35rem;
}
.form-floating > label { color: var(--fh-muted); }
.form-floating > .form-control, .form-floating > .form-select { background-color: var(--fh-soft); }
.form-floating > .form-control:focus, .form-floating > .form-select:focus { background-color: #fff; }

/* --- Cards ------------------------------------------------------------- */
.card {
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-lg);
  box-shadow: var(--fh-shadow-sm);
}
.card-header {
  background: #fff;
  border-bottom: 1px solid var(--fh-border);
  border-top-left-radius: var(--fh-radius-lg);
  border-top-right-radius: var(--fh-radius-lg);
  padding: 0.9rem 1.1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.card-title {
  font-size: var(--fh-text-md);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  margin: 0;
}
.card-tools { display: flex; align-items: center; gap: 0.4rem; }
.card-body { padding: 1.1rem; color: var(--fh-text); }
.card-footer {
  background: #fff;
  border-top: 1px solid var(--fh-border);
  padding: 0.75rem 1.1rem;
  border-bottom-left-radius: var(--fh-radius-lg);
  border-bottom-right-radius: var(--fh-radius-lg);
}
/* The accent stripe itself. This rule used to come from adminlte.min.css
   (`.card-outline{border-top:3px solid var(--lte-card-variant-bg)}`); it is
   restated here because 21 views across Admin, Department, Storage, Sharing
   and Account still use `.card.card-outline.card-*` and would otherwise lose
   their colour band entirely. The variable names are kept as-is so the
   per-variant declarations below did not have to be rewritten.
   Each variant sets `--lte-card-variant-bg` rather than reading
   `--bs-primary`, so the app's own palette drives the accent. */
.card.card-outline {
  border-top-width: 3px;
  border-top-style: solid;
  border-top-color: var(--lte-card-variant-bg, var(--fh-border));
}
.card-primary.card-outline, .card-primary { --lte-card-variant-bg: var(--fh-primary); }
.card-success.card-outline, .card-success { --lte-card-variant-bg: var(--fh-success); }
.card-danger.card-outline, .card-danger { --lte-card-variant-bg: var(--fh-danger); }
.card-warning.card-outline, .card-warning { --lte-card-variant-bg: var(--fh-warning); }
/* Used by Storage/_QuotaCards.cshtml's third stat card; had no declaration of
   its own and fell through to the vendor default. */
.card-secondary.card-outline, .card-secondary { --lte-card-variant-bg: var(--fh-muted); }

/* --- Tables --------------------------------------------------------------
   Mirrors the fh-list-card table treatment (uppercase muted headers,
   soft dividers) for every plain `.table` used outside the Browse grid. */
.table {
  color: var(--fh-text);
  font-size: var(--fh-text-base);
  --bs-table-border-color: var(--fh-border);
}
.table > thead {
  background: var(--fh-soft);
}
.table > thead th {
  border-bottom: 1px solid var(--fh-border);
  color: var(--fh-muted);
  font-weight: var(--fh-weight-semibold);
  font-size: var(--fh-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  white-space: nowrap;
}
.table > :not(caption) > * > * { padding: 0.65rem 0.85rem; }
.table-hover > tbody > tr:hover > * { background-color: var(--fh-primary-soft, #eff6ff); }
.table-sm > :not(caption) > * > * { padding: 0.45rem 0.6rem; }

/* --- Modals ---------------------------------------------------------- */
.modal-content {
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-lg);
  box-shadow: var(--fh-shadow);
}
.modal-header {
  border-bottom: 1px solid var(--fh-border);
  padding: 1rem 1.25rem;
}
.modal-title { font-size: var(--fh-text-lg); font-weight: var(--fh-weight-semibold); color: var(--fh-text); }
.modal-body { padding: 1.25rem; color: var(--fh-text); }
.modal-footer {
  border-top: 1px solid var(--fh-border);
  padding: 0.85rem 1.25rem;
}
.modal-backdrop.show { --bs-backdrop-opacity: 0.35; }

/* --- Shared confirm/alert dialog (replaces window.confirm/alert) ------ */
.fh-dialog .modal-dialog { max-width: 440px; }
.fh-dialog-body {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
}
.fh-dialog-icon {
  flex-shrink: 0;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-xl);
}
.fh-dialog-icon-danger { background: rgba(var(--fh-danger-rgb), 0.1); color: var(--fh-danger); }
.fh-dialog-icon-warning { background: rgba(var(--fh-warning-rgb), 0.12); color: var(--fh-warning); }
.fh-dialog-icon-success { background: rgba(var(--fh-success-rgb), 0.1); color: var(--fh-success); }
.fh-dialog-icon-primary,
.fh-dialog-icon-info { background: rgba(37, 99, 235, 0.1); color: var(--fh-primary); }
.fh-dialog-message { color: var(--fh-text); font-size: var(--fh-text-md); line-height: var(--fh-leading-normal); padding-top: 0.3rem; }

/* --- Toast notifications ------------------------------------------------ */
.fh-toast-host {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  z-index: 1080;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: min(360px, calc(100vw - 2rem));
}
.fh-toast {
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-lg);
  box-shadow: var(--fh-shadow);
  background: #fff;
  border-left: 4px solid var(--fh-primary);
}
.fh-toast-body {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
}
.fh-toast-icon { margin-top: 0.15rem; }
.fh-toast-message { font-size: var(--fh-text-base); color: var(--fh-text); line-height: var(--fh-leading-snug); }
.fh-toast-success { border-left-color: var(--fh-success); }
.fh-toast-success .fh-toast-icon { color: var(--fh-success); }
.fh-toast-error { border-left-color: var(--fh-danger); }
.fh-toast-error .fh-toast-icon { color: var(--fh-danger); }
.fh-toast-warning { border-left-color: var(--fh-warning); }
.fh-toast-warning .fh-toast-icon { color: var(--fh-warning); }
.fh-toast-info { border-left-color: var(--fh-primary); }
.fh-toast-info .fh-toast-icon { color: var(--fh-primary); }

/* --- File preview modal (browse) -------------------------------------- */
#previewModal .modal-content {
  border: 0;
  border-radius: 1rem;
  box-shadow: 0 20px 45px rgba(15, 23, 42, 0.18);
  overflow: hidden;
}
#previewModal .modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  background: #fff;
  border-bottom: 1px solid var(--fh-border);
}
#previewModal .modal-title {
  font-size: var(--fh-text-lg);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#previewModal .modal-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
#previewModal .btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--fh-border);
  border-radius: 0.5rem;
  background: #fff;
  color: var(--fh-muted);
  font-size: var(--fh-text-md);
  text-decoration: none;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
#previewModal .btn-icon:hover {
  background: var(--fh-soft);
  color: var(--fh-text);
  border-color: #cbd5e1;
}
#previewModal #preview-download {
  background: var(--fh-primary);
  border-color: var(--fh-primary);
  color: #fff;
}
#previewModal #preview-download:hover {
  background: var(--fh-primary-dark);
  border-color: var(--fh-primary-dark);
}
#previewModal .modal-body {
  padding: 0;
  background: var(--fh-soft);
}

/* Preview viewport budget. Every preview kind below (iframe, image, video,
   text, markdown) used to hard-code `height: 80vh` — five copies of one
   number that took no account of the modal's own chrome. On a short laptop
   (1280x720, 1366x768) the header plus the centered dialog's margins pushed
   the whole modal to the very edge of the viewport. Subtracting a fixed chrome
   budget makes the preview fit with room to spare on short screens while
   still using 80vh of a tall one, and it's now one number to change. */
:root {
  --fh-preview-h: min(80vh, calc(100vh - 9rem));
}
.fh-preview-frame {
  display: block;
  width: 100%;
  height: var(--fh-preview-h);
  border: 0;
}
.fh-preview-image-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--fh-preview-h);
  overflow: auto;
  padding: 1rem;
}
.fh-preview-image-wrap img {
  max-width: 100%;
  /* Fills the wrap minus its own 1rem padding, rather than a second
     independently-tuned vh number that could drift out of step with it. */
  max-height: 100%;
  object-fit: contain;
}

/* Video Preview */
.fh-preview-video-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--fh-preview-h);
  background: #090d16;
  overflow: hidden;
  padding: 1rem;
}
.fh-preview-video-player {
  max-width: 100%;
  max-height: 100%;
  border-radius: var(--fh-radius);
  outline: none;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}

/* Audio Preview */
.fh-preview-audio-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Bounded against the same preview budget as the other kinds — a bare
     `min-height: 60vh` made this a 1296px-tall band on a 4K display around a
     480px card. */
  min-height: min(60vh, 32rem);
  max-height: var(--fh-preview-h);
  padding: clamp(1.25rem, 0.6rem + 1.6vw, 2.5rem) 1.5rem;
  background: var(--fh-soft);
}
.fh-preview-audio-card {
  background: #fff;
  border-radius: var(--fh-radius);
  padding: 2.5rem 2rem;
  box-shadow: var(--fh-shadow);
  border: 1px solid var(--fh-border);
  text-align: center;
  max-width: 480px;
  width: 100%;
}
.fh-preview-audio-icon {
  width: 76px;
  height: 76px;
  border-radius: 50%;
  background: #fdf2f8;
  color: #db2777;
  font-size: var(--fh-text-5xl);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 1.25rem;
  box-shadow: 0 4px 16px rgba(219, 39, 119, 0.15);
}
.fh-preview-audio-title {
  font-size: var(--fh-text-lg);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  margin-bottom: 0.25rem;
  word-break: break-word;
}
.fh-preview-audio-subtext {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  font-weight: var(--fh-weight-semibold);
  margin-bottom: 1.5rem;
}
.fh-preview-audio-player {
  width: 100%;
  outline: none;
}

/* Text Preview */
.fh-preview-text {
  margin: 0;
  padding: 1rem 1.25rem;
  height: var(--fh-preview-h);
  overflow: auto;
  background: #fff;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fh-text-base);
  line-height: var(--fh-leading-normal);
  white-space: pre-wrap;
  word-break: break-word;
}

/* Markdown Preview */
.fh-preview-md {
  padding: 1.5rem clamp(1rem, 0.4rem + 1.6vw, 2.5rem);
  height: var(--fh-preview-h);
  overflow: auto;
  background: #fff;
  color: var(--fh-text);
}
.fh-preview-md h1, .fh-preview-md h2, .fh-preview-md h3,
.fh-preview-md h4, .fh-preview-md h5, .fh-preview-md h6 {
  margin-top: 1.25rem;
  margin-bottom: 0.5rem;
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
}
.fh-preview-md h1 { font-size: var(--fh-text-3xl); border-bottom: 1px solid var(--fh-border); padding-bottom: 0.3rem; }
.fh-preview-md h2 { font-size: var(--fh-text-2xl); border-bottom: 1px solid var(--fh-border); padding-bottom: 0.25rem; }
.fh-preview-md h3 { font-size: var(--fh-text-xl); }
.fh-preview-md p { margin: 0.5rem 0; line-height: var(--fh-leading-normal); }
.fh-preview-md ul, .fh-preview-md ol { padding-left: 1.5rem; margin: 0.5rem 0; }
.fh-preview-md li { margin-bottom: 0.25rem; }
.fh-preview-md pre {
  background: #f8fafc;
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius);
  padding: 0.85rem 1rem;
  overflow: auto;
  margin: 1rem 0;
}
.fh-preview-md code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fh-text-base);
  color: #0f172a;
}
.fh-preview-md blockquote {
  border-left: 3px solid var(--fh-primary);
  margin: 0.75rem 0;
  padding: 0.5rem 1rem;
  background: rgba(37, 99, 235, 0.03);
  color: var(--fh-muted);
  border-radius: 0 var(--fh-radius) var(--fh-radius) 0;
}
.fh-preview-md hr { border-color: var(--fh-border); margin: 1.5rem 0; opacity: 1; }
.fh-preview-md .fh-md-table {
  width: 100%;
  margin: 1rem 0;
  font-size: var(--fh-text-base);
  border-collapse: collapse;
}
.fh-preview-md .fh-md-table th {
  background: var(--fh-soft);
  font-weight: var(--fh-weight-semibold);
  padding: 0.5rem 0.75rem;
}
.fh-preview-md .fh-md-table td {
  padding: 0.5rem 0.75rem;
}
.fh-preview-md del {
  color: var(--fh-muted);
}

.fh-preview-loading { padding: 4rem 1rem; text-align: center; color: var(--fh-muted); background: #fff; font-size: var(--fh-text-md); }
.fh-preview-message {
  padding: clamp(2rem, 1rem + 2.5vw, 4rem) 2rem;
  text-align: center;
  background: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: min(50vh, 26rem);
}
.fh-preview-message i { font-size: var(--fh-text-6xl); margin-bottom: 1rem; }
.fh-preview-message p { margin: 0; }

/* --- Dropdowns -------------------------------------------------------- */
.dropdown-menu {
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius);
  box-shadow: var(--fh-shadow);
  padding: 0.4rem;
  font-size: var(--fh-text-base);
}
.dropdown-item {
  border-radius: var(--fh-radius-sm);
  padding: 0.45rem 0.7rem;
  color: var(--fh-text);
}
.dropdown-item:hover, .dropdown-item:focus { background: var(--fh-soft); color: var(--fh-text); }
.dropdown-item.active, .dropdown-item:active { background: var(--fh-primary); color: #fff; }
.dropdown-item.text-danger:hover { background: rgba(220, 38, 38, 0.08); color: var(--fh-danger); }
.dropdown-divider { border-color: var(--fh-border); }
.dropdown-header { color: var(--fh-muted); font-size: var(--fh-text-xs); text-transform: uppercase; letter-spacing: var(--fh-tracking-wide); }

/* --- Badges -------------------------------------------------------------
   Bootstrap 5 dropped the Bootstrap-4-style `.badge-*` color modifiers in
   favor of `.text-bg-*`, but several views still use the old class names
   (e.g. `badge-success`, `badge-danger`) — define them so those badges
   render instead of falling back to the plain grey `.badge`. */
.badge {
  border-radius: var(--fh-radius-sm);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-wide);
}
.badge-primary, .badge-info { background-color: var(--fh-primary); color: #fff; }
.badge-secondary { background-color: var(--fh-secondary); color: #fff; }
.badge-success { background-color: var(--fh-success); color: #fff; }
.badge-danger { background-color: var(--fh-danger); color: #fff; }
.badge-warning { background-color: var(--fh-warning); color: #fff; }
.badge-light { background-color: var(--fh-soft); color: var(--fh-text); }
.badge-dark { background-color: var(--fh-text); color: #fff; }

/* --- Pagination -------------------------------------------------------- */
.pagination { gap: 0.25rem; }
.page-link {
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-sm) !important;
  margin-left: 0;
  color: var(--fh-muted);
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-medium);
}
.page-link:hover { background: var(--fh-primary-soft, #eff6ff); border-color: var(--fh-primary-soft-border, #bfdbfe); color: var(--fh-primary); }
.page-link:focus { box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12); }
.page-item.active .page-link { background: var(--fh-primary); border-color: var(--fh-primary); color: #fff; }
.page-item.disabled .page-link { background: #fff; color: #cbd5e1; }

/* --- Navs / tabs (in-page, e.g. Sharing's "with me / by me") ----------- */
.nav-tabs { border-bottom: 1px solid var(--fh-border); }
.nav-tabs .nav-link {
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--fh-muted);
  font-size: var(--fh-text-base);
  font-weight: var(--fh-weight-medium);
  padding: 0.7rem 1rem;
}
.nav-tabs .nav-link:hover { border-color: transparent; color: var(--fh-primary); }
.nav-tabs .nav-link.active {
  color: var(--fh-primary);
  border-bottom-color: var(--fh-primary);
  background: transparent;
}
.nav-pills .nav-link.active { background: var(--fh-primary); }

/* --- Alerts -------------------------------------------------------------- */
.alert {
  border-radius: var(--fh-radius);
  border: 1px solid transparent;
  font-size: var(--fh-text-base);
  padding: 0.85rem 1rem;
}
.alert .btn-close, .alert .close {
  padding: 0.85rem 1rem;
}
/* Old Bootstrap-4-style dismiss trigger (`class="close"` with a literal ×)
   still used on a couple of alert views; give it the same affordance as
   Bootstrap 5's `.btn-close`. */
.close {
  background: transparent;
  border: 0;
  line-height: var(--fh-leading-none);
  font-size: var(--fh-text-2xl);
  color: inherit;
  opacity: 0.6;
  float: right;
  cursor: pointer;
}
.close:hover { opacity: 1; }

/* --- Content well / footer ------------------------------------------------ */
/* Horizontal gutter on the shell cap — vertical well padding lives with the
   consolidated .fh-content rule in the spacing block below. */
/* Gutter scales with the viewport (0.75rem on a phone → 2.5rem on a large
   display) instead of sitting at a flat 1.25rem, which read as cramped on a
   4K panel and as wasteful on a 360px one. min-width:0 stops a wide child
   (a table, a long path) from forcing the whole shell past 100vw. */
.fh-content > .container-fluid {
  padding: 0 var(--fh-gutter, 1.25rem);
  min-width: 0;
}
.fh-footer {
  background: #fff;
  border-top: 1px solid var(--fh-border);
  color: var(--fh-muted);
  font-size: var(--fh-text-xs);
  padding: 0.75rem 1.25rem;
}

@media (max-width: 575.98px) {
  .card-header { padding: 0.75rem 0.9rem; }
  .card-body { padding: 0.9rem; }
  .modal-body, .modal-header, .modal-footer { padding: 0.9rem; }
  /* .fh-content > .container-fluid's padding is handled by --fh-gutter's
     clamp(), which already resolves to 0.75rem at this width. */
}

/* ==========================================================================
   Responsive refinements — mobile-first tweaks that keep the layout usable
   and free of horizontal overflow on small viewports without changing the
   desktop look (the app shell already collapses the sidebar into a drawer
   below the `lg` breakpoint).
   ========================================================================== */

/* Top navbar: let the search field shrink so the brand + actions never force
   the header wider than the viewport. */
.fh-search { min-width: 0; }
.fh-search-input { min-width: 0; }

@media (max-width: 767.98px) {
  .fh-search { margin: 0 0.5rem; }
}

@media (max-width: 575.98px) {
  .fh-navbar { gap: 0.5rem; padding: 0 0.75rem 0 0.5rem; }
  .fh-brand-badge { display: none; }
  .fh-brand-text { display: none; }
  .fh-btn-primary { padding: 0.45rem 0.6rem; }
}

/* The small "⋮" more-actions toggles keep their visual size but grow a
   transparent hit area so they're reliably tappable on touch screens without
   disturbing the card/row layout. */
.fh-card-menu-toggle,
.fh-row-menu-toggle {
  position: relative;
}
.fh-card-menu-toggle::after,
.fh-row-menu-toggle::after {
  content: "";
  position: absolute;
  inset: -9px;
}

/* Touch targets ≥ 44px.
   The trigger is `pointer: coarse` (the input device is a finger or a TV
   remote), not viewport width. Width was the wrong proxy in both directions:
   a 1024x768 tablet and a 4K TV browser are touch/remote-driven but were
   getting mouse-sized 28-36px controls, while a narrow desktop window got
   phone-sized ones it didn't need. The width query is kept alongside so
   narrow layouts still get the comfortable sizing regardless of pointer. */
@media (max-width: 767.98px), (pointer: coarse) {
  .fh-icon-btn { width: 44px; height: 44px; }
  .fh-user-btn { min-height: 44px; }
  .btn { min-height: 44px; }
  .form-control, .form-select { min-height: 44px; }
  .dropdown-item { min-height: 44px; }

  /* The language pill was a 34x28 button inside a 34px-tall track — the
     smallest interactive target in the app and the only one the original
     touch pass missed. */
  .fh-lang-toggle { height: auto; }
  .fh-lang-btn,
  .fh-login-lang-btn { min-width: 44px; min-height: 44px; }

  /* Segmented view toggle: `.btn { min-height: 44px }` above grows the
     segments, so the track has to stop constraining them. */
  .fh-view-toggle .btn { min-height: 40px; }

  /* The "⋮" menus keep their 28px visual size (they sit over card artwork),
     but their transparent hit area grows to a full 44px square rather than
     the 46px-diagonal the -9px inset produced. */
  .fh-card-menu-toggle::after,
  .fh-row-menu-toggle::after { inset: -8px; }
}

/* Keyboard focus for the chrome buttons that aren't Bootstrap `.btn`s and so
   miss the global `.btn:focus-visible` ring. Several of these previously set
   `outline: 0` on focus and relied on a background tint alone, which is not a
   perceivable focus indicator — and `.fh-card-menu-toggle` sits on top of
   card artwork where a tint is invisible. A ring drawn with `outline` (not
   `box-shadow`) survives the `overflow: hidden` on .fh-list-card and the card
   thumbnails, so it stays visible at every breakpoint. */
.fh-icon-btn:focus-visible,
.fh-user-btn:focus-visible,
.fh-menu-toggle:focus-visible,
.fh-card-menu-toggle:focus-visible,
.fh-row-menu-toggle:focus-visible,
.fh-upload-fab:focus-visible,
.fh-segmented-btn:focus-visible,
.fh-upload-dock-btn:focus-visible,
.fh-breadcrumb-list a:focus-visible,
#previewModal .btn-icon:focus-visible {
  outline: 2px solid var(--fh-primary);
  outline-offset: 2px;
}
/* The dock header is dark; a brand-blue ring on it reads poorly. */
.fh-upload-dock-btn:focus-visible {
  outline-color: #93c5fd;
}

/* Keep tall dialogs scrollable within a short viewport. Budgeted against the
   modal's own chrome for the same reason as --fh-preview-h: a flat 65vh took
   no account of the header and footer, so on a 1280x720 laptop the dialog ran
   to the very edge of the screen. */
#shareModal .modal-body,
#fileHistoryModal .modal-body {
  max-height: min(65vh, calc(100vh - 12rem));
  overflow-y: auto;
}

/* ==========================================================================
   Login page — split brand panel + form (FileHub tokens + SiHub logo)
   ========================================================================== */
.fh-login-body {
  margin: 0;
  background: var(--fh-bg);
  font-family: var(--fh-font-sans);
}

.fh-login-root {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  /* 100svh (small viewport height) on mobile: with plain 100vh the page is
     sized to the viewport *without* the browser's collapsible URL bar, so on
     iOS/Android Chrome the login card sat partly under the address bar on
     first paint and the page scrolled by exactly the bar's height. The vh
     line stays first as the fallback for older engines. */
  min-height: 100vh;
  min-height: 100svh;
  width: 100%;
  font-family: var(--fh-font-sans);
  background: var(--fh-bg);
  padding: clamp(1rem, 3vh, 2rem) var(--fh-gutter);
  box-sizing: border-box;
}

.fh-login-shell {
  display: flex;
  flex: 0 1 auto;
  width: min(1100px, 100%);
  min-height: 580px;
  border-radius: var(--bs-border-radius-2xl, 1.25rem);
  overflow: hidden;
  box-shadow: var(--fh-shadow);
  background: #ffffff;
}

.fh-login-mobile-bar {
  display: none;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1.5rem;
  background: var(--fh-primary);
  flex-shrink: 0;
}

.fh-login-mobile-logo {
  background: #ffffff;
  border-radius: var(--fh-radius-sm);
  padding: 4px 6px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.fh-login-mobile-img {
  width: 32px;
  height: 32px;
  object-fit: contain;
  display: block;
}

.fh-login-mobile-title {
  color: #ffffff;
  font-weight: var(--fh-weight-bold);
  font-size: var(--fh-text-md);
  line-height: var(--fh-leading-tight);
}

.fh-login-mobile-sub {
  color: rgba(255, 255, 255, 0.55);
  font-size: var(--fh-text-xs);
  letter-spacing: var(--fh-tracking-wide);
  margin-top: 2px;
}

.fh-login-brand {
  position: relative;
  /* Cap the brand column so ultra-wide screens keep a panel, not a void. */
  flex: 0 0 auto;
  width: clamp(300px, 42%, 480px);
  background: linear-gradient(160deg, var(--fh-primary) 0%, var(--fh-primary-dark) 100%);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1.5rem;
  padding: clamp(1.5rem, 1rem + 1.6vw, 2.75rem) clamp(1.25rem, 0.8rem + 1.2vw, 2.25rem);
  color: #ffffff;
}

.fh-login-brand::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle at center, rgba(255, 255, 255, 0.06) 1.2px, transparent 1.4px);
  background-size: 20px 20px;
  pointer-events: none;
}

.fh-login-brand-header {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.fh-login-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  width: fit-content;
  padding: 0.35rem 0.75rem;
  border-radius: var(--bs-border-radius-pill, 50rem);
  background: rgba(255, 255, 255, 0.1);
  color: #ffffff;
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-wide);
  line-height: var(--fh-leading-none);
}

.fh-login-badge i {
  font-size: var(--fh-text-sm);
  opacity: 0.9;
}

.fh-login-brand-title {
  color: #ffffff;
  font-size: var(--fh-text-4xl);
  font-weight: var(--fh-weight-bold);
  line-height: var(--fh-leading-tight);
  margin: 0;
  letter-spacing: var(--fh-tracking-tighter);
}

.fh-login-brand-center {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
}

.fh-login-logo-card {
  background: #ffffff;
  border-radius: var(--bs-border-radius-2xl, 1.25rem);
  padding: 1.25rem 1.5rem;
  box-shadow: 0 8px 36px rgba(0, 0, 0, 0.22), 0 2px 8px rgba(0, 0, 0, 0.12);
  max-width: 280px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.fh-login-logo-img {
  width: 100%;
  height: auto;
  display: block;
  object-fit: contain;
}

.fh-login-brand-tagline {
  margin: 0;
  color: rgba(255, 255, 255, 0.72);
  font-size: var(--fh-text-sm);
  line-height: var(--fh-leading-normal);
  text-align: center;
  max-width: 22rem;
}

.fh-login-brand-footer {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.fh-login-features {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.fh-login-chip {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.625rem 0.875rem;
  border-radius: var(--fh-radius);
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.92);
  font-size: var(--fh-text-sm);
  line-height: var(--fh-leading-snug);
}

.fh-login-chip i {
  flex-shrink: 0;
  color: #ffffff;
  font-size: var(--fh-text-xs);
}

.fh-login-brand-note {
  color: rgba(255, 255, 255, 0.4);
  font-size: var(--fh-text-xs);
  margin: 0;
  letter-spacing: var(--fh-tracking-wide);
}

.fh-login-form-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: clamp(2rem, 1.5rem + 2vw, 3.5rem) clamp(1.5rem, 1rem + 1.5vw, 3rem);
  position: relative;
  background: #ffffff;
}

.fh-login-form-box {
  width: 100%;
  max-width: 390px;
}

.fh-login-header {
  margin-bottom: 2rem;
}

.fh-login-title {
  font-size: var(--fh-text-4xl);
  font-weight: var(--fh-weight-bold);
  color: var(--fh-text);
  margin: 0;
  letter-spacing: var(--fh-tracking-tighter);
  line-height: var(--fh-leading-tight);
}

.fh-login-subtitle {
  color: var(--fh-muted);
  font-size: var(--fh-text-md);
  margin: 0.625rem 0 0;
  line-height: var(--fh-leading-normal);
}

.fh-login-form {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.fh-login-field {
  display: flex;
  flex-direction: column;
}

.fh-login-label {
  display: block;
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  margin-bottom: 0.5rem;
}

.fh-login-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.fh-login-input-icon {
  position: absolute;
  left: 0.875rem;
  color: var(--fh-muted);
  font-size: var(--fh-text-sm);
  pointer-events: none;
}

.fh-login-input {
  width: 100%;
  height: 46px;
  padding: 0 0.875rem 0 2.5rem;
  border: 1.5px solid var(--fh-border);
  border-radius: var(--fh-radius);
  font-size: var(--fh-text-md);
  color: var(--fh-text);
  background: var(--fh-soft);
  outline: none;
  transition: border-color var(--fh-transition-fast), box-shadow var(--fh-transition-fast);
  font-family: inherit;
  box-sizing: border-box;
}

.fh-login-input::placeholder {
  color: var(--fh-muted);
}

.fh-login-input:focus {
  border-color: var(--fh-primary);
  box-shadow: var(--fh-focus-ring);
  background: #ffffff;
}

.fh-login-pw-wrap .fh-login-input {
  padding-right: 2.75rem;
}

.fh-login-pw-toggle {
  position: absolute;
  right: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.25rem;
  color: var(--fh-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-md);
  transition: color var(--fh-transition-fast);
}

.fh-login-pw-toggle:hover {
  color: var(--fh-text);
}

.fh-login-options {
  display: flex;
  align-items: center;
}

.fh-login-check-label {
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
  user-select: none;
  cursor: pointer;
}

.fh-login-form .form-check-input:checked {
  background-color: var(--fh-primary);
  border-color: var(--fh-primary);
}

.fh-login-submit-btn {
  width: 100%;
  height: 48px;
  background: var(--fh-primary);
  color: #ffffff;
  border: none;
  border-radius: var(--fh-radius);
  font-size: var(--fh-text-md);
  font-weight: var(--fh-weight-semibold);
  cursor: pointer;
  transition: background-color var(--fh-transition-fast), transform 0.1s ease, box-shadow var(--fh-transition-fast);
  font-family: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  box-shadow: var(--fh-shadow-sm);
}

.fh-login-submit-btn:hover {
  background: var(--fh-primary-dark);
  color: #ffffff;
}

.fh-login-submit-btn:focus-visible {
  outline: 2px solid var(--fh-primary);
  outline-offset: 2px;
}

.fh-login-submit-btn:active {
  transform: scale(0.985);
}

.fh-login-secured {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  margin: 1.25rem 0 0;
  color: var(--fh-muted);
  font-size: var(--fh-text-xs);
  line-height: var(--fh-leading-snug);
}

.fh-login-lang-switch {
  margin-top: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}

.fh-login-lang-btn {
  border: 0;
  background: transparent;
  width: 34px;
  height: 28px;
  padding: 0;
  border-radius: var(--bs-border-radius-pill, 50rem);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: all var(--fh-transition-fast);
  cursor: pointer;
  box-sizing: border-box;
}

.fh-login-lang-btn:hover:not(.active) {
  background: rgba(0, 0, 0, 0.04);
}

.fh-login-lang-btn.active {
  background: var(--fh-primary);
  box-shadow: 0 1px 2px rgba(37, 99, 235, 0.2);
  cursor: default;
}

.fh-login-lang-btn:focus-visible {
  outline: 2px solid var(--fh-primary);
  outline-offset: 1px;
}

.fh-login-lang-btn:not(.active) .fh-flag-icon {
  opacity: 0.55;
}

.fh-login-lang-btn:hover:not(.active) .fh-flag-icon {
  opacity: 1;
  transform: scale(1.05);
}

.fh-login-lang-btn.active .fh-flag-icon {
  opacity: 1;
  filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.35));
}

/* .98 upper bound: at exactly 768px the brand panel was hidden *and* the
   desktop two-column rule still applied, so the tablet-portrait login page
   dropped its branding for no reason. */
@media (max-width: 767.98px) {
  .fh-login-root {
    padding: 0;
    justify-content: flex-start;
    align-items: stretch;
  }
  .fh-login-shell {
    flex-direction: column;
    width: 100%;
    min-height: 0;
    flex: 1;
    border-radius: 0;
    box-shadow: none;
  }
  .fh-login-brand {
    display: none;
  }
  .fh-login-mobile-bar {
    display: flex;
  }
  .fh-login-form-panel {
    padding: 2.5rem 1.25rem;
    align-items: center;
    background: var(--fh-soft);
  }
  .fh-login-form-box {
    max-width: 100%;
  }
}
/* --- Storage page (Storage PLAN §4) --- */
.fh-storage-page {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  max-width: 72rem;
}

.fh-storage-quota {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.fh-storage-quota-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.75rem 1.25rem;
}

.fh-storage-quota-value {
  font-size: var(--fh-text-4xl);
  font-weight: var(--fh-weight-bold);
  letter-spacing: var(--fh-tracking-tighter);
  color: var(--fh-text);
  line-height: var(--fh-leading-tight);
}

.fh-storage-quota-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.85rem;
  color: var(--fh-muted);
  font-size: var(--fh-text-base);
}

.fh-storage-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2rem;
}

.fh-storage-fact-value {
  font-size: var(--fh-text-lg);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
}

.fh-storage-fact-label {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
}

.fh-storage-fact-label a {
  color: inherit;
}

.fh-storage-fact-label a:hover {
  color: var(--fh-primary);
}

.fh-storage-hint {
  margin: 0;
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
}

.fh-storage-breakdown {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 1.25rem;
  align-items: start;
}

.fh-storage-section-title {
  margin: 0 0 0.75rem;
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-wide);
  text-transform: uppercase;
  color: var(--fh-muted);
}

.fh-storage-table > .fh-storage-section-title {
  padding: 0.85rem 1rem 0;
  margin-bottom: 0.35rem;
}

.fh-storage-num {
  font-variant-numeric: tabular-nums;
}

.fh-storage-include-trash {
  border-top: 1px solid var(--fh-border);
  padding-top: 0.75rem;
}

.fh-storage-include-trash > summary {
  cursor: pointer;
  font-size: var(--fh-text-base);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-muted);
}

.fh-storage-include-trash > summary:hover {
  color: var(--fh-text);
}

@media (max-width: 991.98px) {
  .fh-storage-breakdown {
    grid-template-columns: 1fr;
  }
}

.fh-storage-cards {
  margin-bottom: 1rem;
}

.fh-stat-card .card-body {
  padding: 0.9rem 1.1rem;
}

.fh-stat-label {
  font-size: var(--fh-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  color: var(--fh-muted);
  margin-bottom: 0.25rem;
}

.fh-stat-value {
  font-size: var(--fh-text-2xl);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
}

.fh-stat-sub {
  font-size: var(--fh-text-xs);
  margin-top: 0.15rem;
}

.fh-storage-bar {
  height: 10px;
  border-radius: var(--fh-radius-sm);
  overflow: hidden;
  background: var(--fh-soft);
}

.fh-storage-bar-free {
  background-color: #cbd5e1 !important;
}

.fh-storage-bar-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.15rem;
}

.fh-legend-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  margin-right: 0.3rem;
}

.fh-storage-progress-sm {
  height: 6px;
  border-radius: var(--fh-radius-sm);
  background: var(--fh-soft);
}

.fh-storage-subtable {
  background: var(--fh-soft);
}

.fh-donut-wrap {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
}

.fh-donut {
  width: 140px;
  height: 140px;
  flex-shrink: 0;
  transform: rotate(-90deg);
}

.fh-donut-track {
  fill: none;
  stroke: var(--fh-soft);
  stroke-width: 3.2;
}

.fh-donut-segment {
  fill: none;
  stroke-width: 3.2;
}

.fh-donut-legend {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 160px;
}

.fh-donut-legend-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--fh-text-base);
}

.fh-donut-legend-label {
  flex: 1;
}

/* ==========================================================================
   Trash Page Custom Aesthetics & Selection Toolbar (PLAN §2.5, Day 7)
   ========================================================================== */

.fh-trash-container {
  min-width: 0;
}

.fh-trash-retention-note {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
}

/* Problems / Conflicts Resolution Card */
.fh-trash-problems-card {
  background: #fffbeb;
  border: 1px solid #fde68a;
  border-radius: 0.65rem;
  padding: 0.75rem 1rem;
}
.fh-trash-problems-header {
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-semibold);
  color: #92400e;
  margin-bottom: 0.5rem;
}
.fh-trash-problems-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.fh-trash-problem-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  background: #ffffff;
  border: 1px solid #fef3c7;
  border-radius: 0.5rem;
  padding: 0.4rem 0.65rem;
  font-size: var(--fh-text-sm);
}
.fh-trash-problem-info {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Toolbar */
.fh-trash-container .fh-list-card tbody tr[data-batch-id] {
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: background-color 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

.fh-trash-btn-restore {
  box-shadow: 0 1px 2px rgba(37, 99, 235, 0.2);
}

/* Main Trash Card */
.fh-trash-card {
  background: #ffffff;
  border: 1px solid var(--fh-border);
  border-radius: 0.85rem;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.03);
}

/* Table */
.fh-trash-table {
  font-size: var(--fh-text-sm);
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
}
.fh-trash-table thead th {
  background: var(--fh-soft);
  color: var(--fh-muted);
  font-weight: var(--fh-weight-semibold);
  font-size: var(--fh-text-xs);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--fh-border);
  border-top: none;
  vertical-align: middle;
}
.fh-trash-table tbody tr {
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: background-color 0.15s ease;
}
.fh-trash-table tbody tr:hover td {
  background-color: var(--fh-primary-soft, #eff6ff);
}
.fh-trash-table tbody tr.is-selected td {
  background-color: var(--fh-primary-soft, #eff6ff) !important;
  color: var(--fh-primary);
}
.fh-trash-table tbody tr.is-selected:hover td {
  background-color: var(--fh-primary-soft, #eff6ff) !important;
  color: var(--fh-primary-dark);
}
.fh-trash-table tbody td {
  padding: 0.75rem 1rem;
  vertical-align: middle;
  border-bottom: 1px solid #f1f5f9;
  color: #334155;
}
.fh-trash-table tbody tr:last-child td {
  border-bottom: none;
}
.fh-trash-item-name {
  font-weight: var(--fh-weight-medium);
  color: var(--fh-text);
  word-break: break-word;
}

/* Empty State */
.fh-trash-empty {
  text-align: center;
  padding: 4.5rem 1.5rem;
}
.fh-trash-empty-icon {
  font-size: var(--fh-text-6xl);
  color: #cbd5e1;
  margin-bottom: 1rem;
}
.fh-trash-empty-title {
  font-size: var(--fh-text-xl);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  margin-bottom: 0.35rem;
}
.fh-trash-empty-subtitle {
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
  max-width: 420px;
  margin: 0 auto;
}

/* Pagination */
.fh-trash-pagination {
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--fh-border);
  background: var(--fh-soft);
  display: flex;
  justify-content: flex-end;
}

/* Helper button */
.btn-xs {
  padding: 0.2rem 0.45rem;
  font-size: var(--fh-text-xs);
  border-radius: 0.35rem;
}

/* --- Content shell spacing / sticky header polish -----------------------
   Started as a Browse-only treatment (chrome-free landing page, sidebar
   collapsed via _Layout.cshtml's old isFocusedSurface) plus the page-header /
   sticky-toolbar polish and overall spacing pass that surface was missing
   (cramped/uneven padding, misaligned grid, no visual hierarchy). The sidebar
   is now collapsed by default everywhere, so this spacing is the global
   default too — the rules below target `.fh-content` directly. */
:root {
  /* Rendered .fh-navbar height — supplies body padding-top, drawer/backdrop
     top inset, and the sticky offset for .fh-content-head. */
  --fh-header-h: 4.25rem;
  /* Vertical rhythm between sections inside .fh-panel — section gap ≥ grid gap
     at every tier so the seam between sections always reads wider than cards. */
  --fh-section-gap: 1.1rem;
  --fh-grid-gap: 1.1rem;
  /* Well padding — the layout .fh-content well only; header band supplies its
     own --fh-head-pad-y immediately below. */
  --fh-well-pad-top: 1.25rem;
  --fh-well-pad-bottom: 2rem;
  --fh-radius-xl: 0.85rem;
  --fh-row-pad-y: 0.75rem;
  --fh-row-pad-x: 1rem;
  --fh-float-inset: 1.5rem;
  --fh-selected-bg: #f0f7ff;
  --fh-selected-bg-hover: #e0effe;
  /* Header band rhythm — declared once so .fh-content-head's own spacing can't
     drift out of step with the grid it sits above.
     --fh-head-inset is shared with .fh-grid's horizontal padding: the
     breadcrumb/title column must line up with the card column below it, so
     these two are deliberately the same number in one place.
     --fh-head-pad-y is the band's vertical breathing room; --fh-head-gap is
     the seam between the breadcrumb and the title/actions row (larger than the
     gaps *inside* that row, so the hierarchy reads top-to-bottom). */
  --fh-head-inset: 0.25rem;
  --fh-head-pad-y: 1rem;
  --fh-head-gap: 0.9rem;
}
@media (max-width: 575.98px) {
  :root {
    --fh-section-gap: 0.9rem;
    --fh-grid-gap: 0.65rem;
    --fh-well-pad-top: 0.75rem;
    --fh-well-pad-bottom: 1.25rem;
    --fh-radius-xl: 0.75rem;
    --fh-float-inset: 1rem;
    --fh-head-pad-y: 0.7rem;
    --fh-head-gap: 0.65rem;
  }
}

@media (min-width: 576px) and (max-width: 767.98px) {
  :root { --fh-grid-gap: 0.85rem; }
}
@media (min-width: 768px) and (max-width: 1023.98px) {
  :root { --fh-grid-gap: 1rem; }
}
@media (min-width: 1440px) and (max-width: 1919.98px) {
  :root {
    --fh-section-gap: 1.25rem;
    --fh-grid-gap: 1.25rem;
  }
}
@media (min-width: 1920px) and (max-width: 2559.98px) {
  :root {
    --fh-section-gap: 1.4rem;
    --fh-grid-gap: 1.4rem;
  }
}
@media (min-width: 2560px) and (max-width: 3839.98px) {
  :root {
    --fh-section-gap: 1.6rem;
    --fh-grid-gap: 1.6rem;
  }
}
@media (min-width: 3840px) {
  :root {
    --fh-section-gap: 1.85rem;
    --fh-grid-gap: 1.85rem;
  }
}

/* Content well — background, horizontal breathing room, and vertical padding. */
.fh-content {
  background-color: var(--fh-bg);
  padding-top: var(--fh-well-pad-top);
  padding-bottom: var(--fh-well-pad-bottom);
}

/* Widen the content gutter — the grid would otherwise stretch edge-to-edge on
   wide monitors. The cap applies to whatever width .fh-main currently has, so
   in push mode it is measured against what is left after the open sidebar's
   column and the content re-centres inside the narrowed well.

   This was a flat `max-width: 1440px`, which reads as "centered and readable"
   up to about 1680px and as a defect above it: on a 3440x1440 ultra-wide the
   file grid occupied 42% of the panel, and on a 4K TV 37%, with the rest left
   as empty grey. `--fh-shell-max` ramps the cap with the viewport instead, so
   large displays actually gain columns, while still never running the cards
   flush to the bezel. See the token's definition in the wide-screen block. */
.fh-content > .container-fluid {
  max-width: var(--fh-shell-max);
  margin-inline: auto;
}

/* Sticky header block — two rows: the breadcrumb, then .fh-content-head-main
   (title + count on the left, controls on the right). `--fh-head-gap` between
   them is deliberately wider than any gap *inside* either row, so the band
   reads as a hierarchy rather than a stack of equally-weighted strips.
   The bottom padding is trimmed against the top because .fh-content's
   `--fh-section-gap` already contributes to the header → grid seam; without
   that trim the seam came out at roughly twice every other one on the page.
   The 1px border only appears once scrolled (.is-stuck, toggled by browse.js's
   IntersectionObserver on #content-head-sentinel), so at rest it blends in. */
.fh-content-head {
  position: sticky;
  top: var(--fh-header-h);
  z-index: 1020; /* below the 1030-1050 chrome band and .fh-dropdown's 1060 */
  display: flex;
  flex-direction: column;
  gap: var(--fh-head-gap);
  background: var(--fh-bg);
  margin-inline: calc(-1 * var(--fh-gutter));
  padding: var(--fh-head-pad-y) calc(var(--fh-gutter) + var(--fh-head-inset))
           calc(var(--fh-head-pad-y) * 0.75);
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/* Once stuck, the band must read unmistakably as a bar that content passes
   *under*. Its background is --fh-bg — the exact page background — so with
   only a 1px border and a 2px shadow a card sliding beneath it looked
   decapitated rather than tucked: the missing strip had no edge to explain
   it. Measured from a report at 2x, ~6.5px of a card's top sat under the band
   with no visible boundary at all.

   Solid surface + a real drop shadow gives the overlap an explanation. */
.fh-content-head.is-stuck {
  background: #fff;
  border-bottom-color: var(--fh-border);
  box-shadow: 0 4px 12px -2px rgba(15, 23, 42, 0.10),
              0 2px 4px -2px rgba(15, 23, 42, 0.06);
}

/* Two sticky layers stack above the grid: the app header (--fh-header-h) and
   .fh-content-head below it. Anything scrolled into view — a focused card, an
   anchor target, a restored scroll position after a content-panel refresh —
   has to clear BOTH, or it lands underneath the opaque .fh-content-head band
   with its top edge and "⋯" button hidden, which reads as the card being
   clipped rather than tucked under a bar.

   .fh-content-head's own height is content-dependent (one row on a laptop,
   two once the toolbar wraps below 768px), so CSS can't read it; --fh-sticky-
   stack budgets a generous constant for the band on top of the header token
   it can read. Erring long only costs a little extra headroom above the
   scrolled-to card. */
:root {
  --fh-sticky-stack: calc(var(--fh-header-h, 3.5rem) + 6rem);
}
@media (max-width: 767.98px) {
  :root {
    /* The toolbar wraps to its own row here, so the band is taller. */
    --fh-sticky-stack: calc(var(--fh-header-h, 3.5rem) + 9rem);
  }
}

html {
  scroll-padding-top: var(--fh-sticky-stack);
}
.fh-card,
.fh-grid-section,
#list-view tbody tr {
  scroll-margin-top: var(--fh-sticky-stack);
}

/* The balanced header row: title cluster grows to fill, control cluster keeps
   its natural width at the far end. Below 768px it wraps and the toolbar takes
   a full row of its own (see the media query further down). */
.fh-content-head-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--fh-head-gap);
  min-width: 0;
}

/* Page header — folder name as the page's actual title, with the item count as
   a muted chip inline beside it (rather than a second stacked line, which read
   as a competing heading and cost the band an extra row of height). */
/* flex-basis (not `auto`) gives the title cluster a floor: once the toolbar can
   no longer sit beside 14rem of title, .fh-content-head-main wraps and the
   toolbar takes its own row — rather than the title being crushed to a couple
   of ellipsized characters to keep everything on one line. `min-width: 0` is
   still needed for .fh-page-title's ellipsis to engage below that. */
.fh-page-header {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.6rem;
  flex: 1 1 14rem;
  min-width: 0;
  order: 0;
}
.fh-page-title {
  margin: 0;
  font-size: var(--fh-text-3xl);
  font-weight: var(--fh-weight-bold);
  letter-spacing: var(--fh-tracking-tight);
  color: var(--fh-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
/* Folder glyph tile beside the title — same tinted-tile treatment as
   .fh-card-icon.icon-folder, sized down for the header band. */
.fh-page-title-icon {
  flex-shrink: 0;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 0.65rem;
  background: rgba(245, 158, 11, 0.12);
  color: #f59e0b;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-lg);
}
.fh-page-title-icon-storage {
  background: rgba(59, 130, 246, 0.12);
  color: #3b82f6;
}
@media (max-width: 575.98px) {
  .fh-page-title {
    font-size: var(--fh-text-2xl);
  }
  .fh-page-title-icon {
    width: 1.8rem;
    height: 1.8rem;
    font-size: var(--fh-text-md);
  }
}

/* Toolbar clusters wrap onto their own full-width line as a group on narrow
   screens (touch targets already ≥44px via the responsive-refinements block
   above), reverting to space-between so "+ New" stays pinned to the right
   edge, with extra row-gap so two stacked rows don't feel glued together. */
@media (max-width: 767.98px) {
  .fh-toolbar {
    flex-basis: 100%;
    justify-content: space-between;
    row-gap: 0.75rem;
  }
}

/* Empty-state CTA — subtitle + (Edit-level) Upload button under the existing
   icon/title, so an empty landing folder isn't just a dead end. */
.fh-empty-title {
  color: var(--fh-text);
  font-weight: var(--fh-weight-semibold);
  margin-bottom: 0.25rem;
}
.fh-empty-sub {
  color: var(--fh-muted);
  margin-bottom: 1rem;
}
.fh-empty .btn {
  margin-top: 0.25rem;
}
@media (max-width: 575.98px) {
  .fh-empty {
    padding: 2rem 1.25rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fh-content-head {
    transition: none;
  }
}

/* ==== Empty-space marquee & context menu (browse.js) ================== */

/* The marquee band has to scroll WITH the grid (unlike the position:fixed
   "..." menus), so .fh-main must be its containing block rather than <body>.
   `position: relative` is declared in the app-shell block at the top of this
   file, alongside the rest of .fh-main's geometry. `relative` is inert for the
   sticky .fh-content-head and for the fixed .fh-selection-toolbar /
   .fh-dropdown — only transform/filter would affect those. */

/* Rubber-band selection rectangle, drawn while dragging on empty grid space.
   z-index sits over the cards but under the sticky .fh-content-head (1020),
   the selection toolbar (1035), and every menu. */
.fh-marquee {
  position: absolute;
  z-index: 1010;
  pointer-events: none; /* must never intercept the drag it visualizes */
  border: 1px solid var(--fh-primary);
  background: rgba(37, 99, 235, 0.12);
  border-radius: 2px;
}

/* Applied only once a drag passes the 6px threshold, so an ordinary click
   never loses text selection or focus. */
body.is-marquee-active,
body.is-marquee-active * {
  user-select: none;
  -webkit-user-select: none;
}
body.is-marquee-active {
  cursor: default;
}
/* Stops the native image/link drag ghost when the band sweeps over a card. */
body.is-marquee-active .fh-card img,
body.is-marquee-active .fh-card a {
  -webkit-user-drag: none;
  pointer-events: none;
}

/* Right-click menu for empty space. .fh-dropdown supplies the border, shadow,
   radius and z-index (1060); position:fixed anchors it to the viewport, the
   same way the item "..." menus do. */
.fh-context-menu {
  position: fixed;
  min-width: 12rem;
}

/* --- Right-side Details / Information panel (.fh-details-panel) ----------- */
/* Offcanvas details panel — 90vw keeps it on-screen on a 360px phone, while
   the upper bound grows modestly on large displays so a 4K panel doesn't show
   a 360px sliver of metadata against a 3840px page. */
.fh-details-panel {
  width: clamp(min(360px, 90vw), 24vw, 30rem);
  max-width: 90vw;
}

.fh-details-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0 1.25rem;
  margin-bottom: 1rem;
  text-align: center;
  border-bottom: 1px solid var(--fh-border);
}

.fh-details-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Tracks the panel, which is itself fluid now. Square via aspect-ratio
     rather than a matched height, so the two stay in step. */
  width: clamp(6rem, 42%, 11rem);
  aspect-ratio: 1;
  height: auto;
  overflow: hidden;
  object-fit: cover;
  background: #fff;
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-lg);
  box-shadow: var(--fh-shadow-sm);
}

.fh-details-thumb--icon {
  font-size: var(--fh-text-6xl);
}

.fh-details-hero-name {
  max-width: 100%;
  font-size: var(--fh-text-lg);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  word-break: break-word;
}

.fh-details-hero-sub {
  font-size: var(--fh-text-base);
  color: var(--fh-muted);
}

.fh-details-props {
  margin: 0;
  padding: 0;
  list-style: none;
}

.fh-details-prop {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--fh-border);
}

.fh-details-prop:last-child {
  border-bottom: none;
}

.fh-details-prop dt {
  flex: 0 0 40%;
  margin: 0;
  font-size: var(--fh-text-base);
  font-weight: var(--fh-weight-medium);
  color: var(--fh-muted);
}

.fh-details-prop dd {
  flex: 1;
  margin: 0;
  font-size: var(--fh-text-base);
  color: var(--fh-text);
  text-align: right;
  word-break: break-word;
}

.fh-details-prop dd a {
  color: var(--fh-primary);
  text-decoration: none;
}

.fh-details-prop dd a:hover {
  text-decoration: underline;
}

/* ==========================================================================
   Permissions workspace (.fh-permissions-*) — Admin /Admin/Permissions and
   Department /Department/Permissions share Views/Shared/_PermissionsWorkspace.
   Two panes (tree | detail) fill the leftover viewport under the navbar, the
   same idea as Admin Files. Grant and user-access inspect are disclosures,
   not stacked cards. Scoped so /drive, Search, and Admin Files are untouched.
   ========================================================================== */

html:has(body.fh-permissions) {
  height: 100%;
  height: 100vh;
  height: 100dvh;
}
body.fh-permissions {
  --fh-permissions-well-pad: 0.5rem;
  height: 100%;
  overscroll-behavior: none;
}
@media (max-width: 767.98px) {
  body.fh-permissions { --fh-permissions-well-pad: 0px; }
}

body.fh-permissions .fh-shell {
  height: 100%;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
body.fh-permissions .fh-main {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
body.fh-permissions .fh-content {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: var(--fh-permissions-well-pad) 0;
}
body.fh-permissions .fh-content > .container-fluid {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  max-width: none;
  width: 100%;
  padding: 0 var(--fh-permissions-well-pad);
  display: flex;
  flex-direction: column;
}

.fh-permissions-container {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 0;
  /* Remaining viewport after the fixed navbar and this page's well padding.
     Footer is omitted for Permissions in _Layout, so it is not subtracted.
     minmax(0, 1fr) on the detail track (below) is the real overflow fix —
     a bare 1fr blew the page width. */
  height: calc(100vh - var(--fh-header-h) - (2 * var(--fh-permissions-well-pad)));
  height: calc(100dvh - var(--fh-header-h) - (2 * var(--fh-permissions-well-pad)));
  max-height: 100%;
  overflow: hidden;
  border: 1px solid var(--fh-border);
  border-radius: var(--fh-radius-lg);
  background: #fff;
}

.fh-permissions-layout {
  display: grid;
  /* minmax(0, 1fr), not a bare 1fr (== minmax(auto, 1fr)) — a bare 1fr track's
     implicit minimum is its content's min-content width, so wide-enough
     detail-panel content would force this whole grid wider than the viewport. */
  grid-template-columns: minmax(280px, clamp(20rem, 22vw, 28rem)) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  height: 100%;
  align-items: stretch;
}
@media (min-width: 1920px) {
  .fh-permissions-layout {
    grid-template-columns: minmax(280px, clamp(22rem, 20vw, 32rem)) minmax(0, 1fr);
  }
}

.fh-permissions-tree-panel,
.fh-permissions-detail-panel {
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.fh-permissions-tree-panel {
  border-right: 1px solid var(--fh-border);
  padding: 0.75rem;
  gap: 0.6rem;
  background: #fff;
}
.fh-permissions-detail-panel {
  position: relative;
  background: #fff;
}

.fh-permissions-tree-panel::-webkit-scrollbar,
.fh-permissions-detail-panel::-webkit-scrollbar,
.fh-permissions-tree::-webkit-scrollbar,
.fh-permissions-access::-webkit-scrollbar,
.fh-permissions-inspect::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
.fh-permissions-tree-panel::-webkit-scrollbar-thumb,
.fh-permissions-detail-panel::-webkit-scrollbar-thumb,
.fh-permissions-tree::-webkit-scrollbar-thumb,
.fh-permissions-access::-webkit-scrollbar-thumb,
.fh-permissions-inspect::-webkit-scrollbar-thumb {
  background-color: #cbd5e1;
  border-radius: 3px;
}
.fh-permissions-tree-panel::-webkit-scrollbar-track,
.fh-permissions-detail-panel::-webkit-scrollbar-track,
.fh-permissions-tree::-webkit-scrollbar-track,
.fh-permissions-access::-webkit-scrollbar-track,
.fh-permissions-inspect::-webkit-scrollbar-track {
  background: transparent;
}

.fh-permissions-tree-panel .fh-search-box { flex-shrink: 0; }

.fh-permissions-tree {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  min-height: 0;
  border: 0;
  padding: 0;
  background: transparent;
}

/* Empty ("no matches") and error states share one layout — icon over a short
   message, centered in the space the tree would otherwise fill. */
.fh-permissions-tree-state {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 1.5rem 1rem;
  text-align: center;
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
}

.fh-permissions-tree-state-icon {
  font-size: var(--fh-text-3xl);
  color: var(--fh-muted);
}

.fh-permissions-tree-state.is-error .fh-permissions-tree-state-icon {
  color: var(--fh-warning);
}

.fh-permissions-tree-state.is-error {
  color: var(--fh-text);
}

/* permissions.js renders `ul.picker-tree` / `ul.picker-tree-children` — neither
   was styled, so the lists kept Bootstrap Reboot's 2rem padding-left and 1rem
   bottom margin. Reset the lists and drive the indent from --tree-depth. */
.fh-permissions-tree .picker-tree,
.fh-permissions-tree .picker-tree-children {
  list-style: none;
  margin: 0;
  padding-left: 0;
}

.fh-permissions-tree .picker-tree-row {
  padding-left: calc(0.6rem + var(--tree-depth, 0) * 0.85rem);
}

.fh-permissions-tree .picker-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.fh-permissions-tree .picker-toggle i {
  font-size: var(--fh-text-xs);
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.fh-permissions-tree .picker-toggle.is-open i {
  transform: rotate(90deg);
}

.fh-permissions-tree .picker-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fh-permissions-tree .picker-tree-empty {
  padding: 1.25rem 0.5rem;
  text-align: center;
  font-size: var(--fh-text-sm);
  color: var(--fh-muted, #6b7280);
}

.fh-permissions-tree-count {
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  margin-left: auto;
  padding: 0.05rem 0.4rem;
  border-radius: 9999px;
  background-color: #e0e7ff;
  color: #3730a3;
  flex-shrink: 0;
}

/* Owner tag on personal "My Files" tree nodes — quiet by design. The folder
   name is the part that truncates (see .picker-label). */
.fh-permissions-owner-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  max-width: 100%;
  margin-left: 0.35rem;
  padding: 0.05rem 0.45rem;
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-medium);
  color: var(--fh-muted, #6b7280);
  background-color: var(--fh-soft, #f8fafc);
  border: 1px solid var(--fh-border, #e2e8f0);
  border-radius: 9999px;
  flex-shrink: 0;
}

.fh-permissions-owner-tag i {
  font-size: var(--fh-text-2xs);
  flex-shrink: 0;
}

.fh-permissions-owner-tag-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fh-permissions-detail-panel > .fh-empty {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}

.fh-permissions-detail-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  padding: var(--fh-head-pad-y, 0.65rem) 1rem;
  border-bottom: 1px solid var(--fh-border);
  background: #fff;
  min-width: 0;
}

.fh-permissions-detail-header-left {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

.fh-permissions-back {
  display: none;
  flex-shrink: 0;
}

.fh-permissions-folder-title {
  font-size: var(--fh-text-lg);
  font-weight: var(--fh-weight-bold);
  color: var(--fh-text, #0f172a);
  margin: 0;
  line-height: var(--fh-leading-tight);
}

.fh-permissions-folder-sub {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted, #6b7280);
  margin-top: 0.1rem;
}

.fh-permissions-detail-actions {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

.fh-permissions-layout.is-granting #permGrantToggle {
  box-shadow: inset 0 0 0 1px var(--fh-primary, #2563eb);
}

.fh-permissions-layout.is-inspecting #permInspectToggle {
  color: var(--fh-primary, #2563eb);
  background: var(--fh-soft, #f8fafc);
}

.fh-permissions-access {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.fh-permissions-access > .fh-empty {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}

.fh-permissions-access-toolbar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.65rem 1rem 0.5rem;
  min-width: 0;
}

.fh-permissions-access-toolbar .fh-segmented-control {
  flex-shrink: 0;
}

.fh-permissions-access-toolbar .fh-permissions-search-wrap {
  flex: 1 1 10rem;
  min-width: 0;
}

.fh-permissions-container .fh-segmented-control {
  display: inline-flex;
  flex-wrap: nowrap;
  background-color: var(--fh-soft, #f1f5f9);
  padding: 3px;
  border-radius: 0.5rem;
  gap: 2px;
}

.fh-permissions-container .fh-segmented-btn {
  padding: 0.25rem 0.75rem;
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-medium);
  color: var(--fh-muted, #6b7280);
  border-radius: 0.38rem;
  border: none;
  background: transparent;
  cursor: pointer;
  transition: all 0.15s ease;
  user-select: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  white-space: nowrap;
}

.fh-permissions-container .fh-segmented-btn:hover {
  color: var(--fh-primary);
}

.fh-permissions-container .btn-check:checked + .fh-segmented-btn {
  background-color: #fff;
  color: var(--fh-primary);
  font-weight: var(--fh-weight-semibold);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
}

.fh-permissions-search-wrap {
  position: relative;
  width: 100%;
}

.fh-permissions-search-icon {
  position: absolute;
  left: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--fh-muted, #6b7280);
  font-size: var(--fh-text-base);
  pointer-events: none;
}

.fh-permissions-search-input {
  padding-left: 2.3rem;
  border-radius: 0.5rem;
  font-size: var(--fh-text-base);
  border: 1px solid var(--fh-border, #e2e8f0);
  width: 100%;
}

.fh-permissions-search-input:focus {
  border-color: #93c5fd;
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
  outline: none;
}

.fh-permissions-ace-table th {
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  color: var(--fh-muted, #6b7280);
  background-color: #fff;
  padding: 0.65rem 1rem;
  border-bottom: 1px solid var(--fh-border, #e2e8f0);
}

.fh-permissions-ace-table td {
  padding: 0.55rem 1rem;
  vertical-align: middle;
  border-bottom: 1px solid #f1f5f9;
}

.fh-permissions-ace-table th:nth-child(2),
.fh-permissions-ace-table td:nth-child(2),
.fh-permissions-ace-table th:nth-child(3),
.fh-permissions-ace-table td:nth-child(3) {
  width: 1%;
  white-space: nowrap;
}

.fh-permissions-ace-level {
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  padding: 0.25rem 0.65rem;
  border-radius: 9999px;
  white-space: nowrap;
  display: inline-block;
}

.fh-permissions-container .fh-badge-soft-success {
  background-color: #dcfce7;
  color: #15803d;
  border: 1px solid #bbf7d0;
}

.fh-permissions-container .fh-badge-soft-warning {
  background-color: #fef3c7;
  color: #b45309;
  border: 1px solid #fde68a;
}

.fh-permissions-container .fh-badge-soft-info {
  background-color: #dbeafe;
  color: #1d4ed8;
  border: 1px solid #bfdbfe;
}

.fh-permissions-container .fh-badge-soft-danger {
  background-color: #fee2e2;
  color: #b91c1c;
  border: 1px solid #fca5a5;
}

.fh-permissions-container .fh-badge-soft-secondary {
  background-color: #f1f5f9;
  color: var(--fh-muted);
  border: 1px solid #e2e8f0;
}

.fh-permissions-container .fh-avatar-sm {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: linear-gradient(135deg, #3b82f6, #4f46e5);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-bold);
  margin-right: 0.5rem;
  flex-shrink: 0;
  vertical-align: middle;
}

.fh-permissions-principal {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}

.fh-permissions-principal .fh-avatar-sm {
  margin-right: 0;
}

.fh-permissions-dept-icon {
  color: var(--fh-muted, #6b7280);
  width: 1.1em;
  text-align: center;
  flex-shrink: 0;
}

.fh-permissions-ace-info,
.fh-permissions-source-link,
.fh-permissions-ace-lock {
  color: var(--fh-muted, #6b7280);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  flex-shrink: 0;
  border-radius: 0.25rem;
}

.fh-permissions-source-link:hover,
.fh-permissions-ace-info:hover {
  color: var(--fh-primary, #2563eb);
  text-decoration: none;
}

.fh-permissions-ace-lock {
  cursor: default;
}

.fh-permissions-ace-info:focus-visible,
.fh-permissions-ace-lock:focus-visible,
.fh-permissions-source-link:focus-visible {
  outline: 2px solid var(--fh-primary, #2563eb);
  outline-offset: 2px;
}

.fh-permissions-grant,
.fh-permissions-inspect {
  display: none;
  flex-shrink: 0;
  border-bottom: 1px solid var(--fh-border);
  background: #fff;
  padding: 0.75rem 1rem;
}

.fh-permissions-layout.is-granting .fh-permissions-grant {
  display: block;
}

.fh-permissions-layout.is-inspecting .fh-permissions-inspect {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  border-bottom: 0;
}

.fh-permissions-layout.is-inspecting .fh-permissions-access,
.fh-permissions-layout.is-inspecting .fh-permissions-grant {
  display: none;
}

.fh-permissions-grant-who {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.65rem;
  align-items: start;
  margin-bottom: 0.65rem;
}

.fh-permissions-level-row {
  display: flex;
  flex-wrap: nowrap;
  gap: 0.35rem;
  margin-bottom: 0.5rem;
}

.fh-permissions-level-option {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--fh-border, #e2e8f0);
  border-radius: 0.5rem;
  cursor: pointer;
  background: #fff;
  min-width: 0;
  transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}

.fh-permissions-level-option:hover {
  border-color: #93c5fd;
}

.fh-permissions-level-option.is-checked {
  border-color: var(--fh-primary, #2563eb);
  background-color: var(--fh-primary-soft, #eff6ff);
  box-shadow: 0 0 0 1px var(--fh-primary, #2563eb);
}

.fh-permissions-level-title {
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text, #1e293b);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fh-permissions-level-option.is-checked .fh-permissions-level-title {
  color: var(--fh-primary, #2563eb);
}

.fh-permissions-grant-hint {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--fh-text-xs);
  color: var(--fh-muted, #6b7280);
  margin-top: 0.35rem;
}

.fh-permissions-grant-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.65rem;
}

.fh-permissions-picker {
  position: relative;
  width: 100%;
  min-width: 0;
}

.fh-permissions-picker-input-wrap {
  position: relative;
}

.fh-permissions-picker-icon {
  position: absolute;
  left: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--fh-muted, #6b7280);
  font-size: var(--fh-text-base);
  pointer-events: none;
}

.fh-permissions-picker-input {
  padding-left: 2.2rem;
  border-radius: 0.5rem;
  font-size: var(--fh-text-base);
  border: 1px solid var(--fh-border, #e2e8f0);
}

.fh-permissions-picker-input:focus {
  border-color: #93c5fd;
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
  outline: none;
}

.fh-permissions-picker-list {
  position: absolute;
  z-index: 1035;
  top: calc(100% + 0.3rem);
  left: 0;
  right: 0;
  max-height: min(240px, 50vh);
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--fh-border, #e2e8f0);
  border-radius: 0.6rem;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
  padding: 0.3rem;
}

.fh-permissions-picker-option {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 0.45rem 0.6rem;
  border: 0;
  background: none;
  text-align: left;
  font-size: var(--fh-text-sm);
  color: var(--fh-text, #1e293b);
  border-radius: 0.4rem;
  cursor: pointer;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
}

.fh-permissions-picker-option:hover,
.fh-permissions-picker-option:focus-visible {
  background-color: var(--fh-soft, #f8fafc);
  outline: none;
}

.fh-permissions-picker-option:focus-visible {
  box-shadow: inset 0 0 0 2px rgba(37, 99, 235, 0.35);
}

.fh-permissions-picker-empty {
  padding: 0.6rem 0.5rem;
  font-size: var(--fh-text-sm);
  color: var(--fh-muted, #6b7280);
}

.fh-permissions-useraccess-form {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  flex-shrink: 0;
}

.fh-permissions-useraccess-picker {
  flex: 1;
  min-width: 0;
}

.fh-permissions-useraccess-result {
  margin-top: 0.75rem;
  min-width: 0;
}

.fh-permissions-useraccess-banner {
  font-size: var(--fh-text-sm);
  color: var(--fh-text);
  margin: 0;
}

.fh-permissions-useraccess-table th {
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--fh-tracking-wide);
  color: var(--fh-muted, #6b7280);
  background-color: #fff;
  padding: 0.65rem 1rem;
  border-bottom: 1px solid var(--fh-border, #e2e8f0);
}

.fh-permissions-useraccess-table td {
  padding: 0.55rem 1rem;
  vertical-align: middle;
  border-bottom: 1px solid #f1f5f9;
}

.fh-permissions-useraccess-table th:nth-child(2),
.fh-permissions-useraccess-table td:nth-child(2) {
  width: 1%;
  white-space: nowrap;
}

.fh-permissions-useraccess-row {
  cursor: pointer;
  transition: background-color 0.12s ease;
}

.fh-permissions-useraccess-row:hover {
  background-color: var(--fh-soft, #f8fafc);
}

.fh-permissions-useraccess-path {
  max-width: clamp(11rem, 36vw, 48rem);
  display: inline-block;
  vertical-align: middle;
  color: var(--fh-text, #1e293b);
  font-size: var(--fh-text-base);
}

/* Lift overflow clips while a picker list is open so the absolute list is not
   trapped by the pane scroller (same idea as Admin Files' dropdown :has()). */
.fh-permissions-container:has(.fh-permissions-picker-list:not(.d-none)),
.fh-permissions-detail-panel:has(.fh-permissions-picker-list:not(.d-none)),
.fh-permissions-grant:has(.fh-permissions-picker-list:not(.d-none)),
.fh-permissions-inspect:has(.fh-permissions-picker-list:not(.d-none)) {
  overflow: visible;
}

/* Phone + tablet: one column. Landing = tree; .is-browsing (set in the
   Razor when a folder is selected) = detail only. The back control is a
   real link to Index (no folderId). Laptop two-pane starts at 1200px. */
@media (max-width: 1199.98px) {
  .fh-permissions-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  .fh-permissions-tree-panel {
    border-right: 0;
  }
  .fh-permissions-layout:not(.is-browsing) .fh-permissions-detail-panel {
    display: none;
  }
  .fh-permissions-layout.is-browsing .fh-permissions-tree-panel {
    display: none;
  }
  .fh-permissions-back {
    display: inline-flex;
  }
}

@media (max-width: 767.98px) {
  .fh-permissions-container {
    border-radius: 0;
    border-left: 0;
    border-right: 0;
    border-bottom: 0;
  }
  .fh-permissions-grant-who {
    grid-template-columns: minmax(0, 1fr);
  }
  .fh-permissions-grant-toggle-label {
    display: none;
  }
  .fh-permissions-level-row {
    flex-wrap: wrap;
  }
  .fh-permissions-level-option {
    flex: 1 1 calc(50% - 0.35rem);
  }
  .fh-permissions-layout.is-granting .fh-permissions-grant {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 4;
    display: flex;
    flex-direction: column;
    overflow: auto;
    max-height: min(65vh, calc(100vh - 12rem));
    max-height: min(65dvh, calc(100dvh - 12rem));
    border-bottom: 1px solid var(--fh-border);
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
  }
  .fh-permissions-grant-actions .btn {
    flex: 1 1 auto;
  }
  .fh-permissions-access-toolbar {
    flex-wrap: wrap;
  }
  .fh-permissions-access-toolbar .fh-segmented-control {
    width: 100%;
  }
  .fh-permissions-access-toolbar .fh-segmented-btn {
    flex: 1 1 0;
  }
  .fh-permissions-ace-table .fh-permissions-ace-info {
    display: none;
  }
  .fh-permissions-useraccess-form {
    flex-wrap: wrap;
  }
  .fh-permissions-useraccess-form > * {
    min-width: 0;
  }
  .fh-permissions-useraccess-path {
    max-width: 180px;
  }
  .fh-permissions-tree .picker-tree-row {
    flex-wrap: wrap;
    row-gap: 0.15rem;
  }
  .fh-permissions-tree .picker-label {
    flex-basis: auto;
  }
  .fh-permissions-owner-tag {
    max-width: calc(100% - 1.75rem);
  }
  .fh-permissions-owner-tag-text {
    max-width: 100%;
  }
}

@media (max-width: 767.98px), (pointer: coarse) {
  .fh-permissions-container .fh-segmented-btn {
    min-height: 44px;
  }
  .fh-permissions-container .fh-permissions-level-option {
    min-height: 44px;
  }
  .fh-permissions-container .picker-tree-row {
    min-height: 44px;
  }
  .fh-permissions-container .fh-permissions-picker-option {
    min-height: 44px;
  }
  .fh-permissions-container .fh-permissions-ace-info,
  .fh-permissions-container .fh-permissions-source-link,
  .fh-permissions-container .fh-permissions-ace-lock {
    width: 44px;
    height: 44px;
  }
}

@media (max-width: 575.98px) {
  .fh-permissions-ace-table tbody td,
  .fh-permissions-ace-table thead th {
    padding: 0.5rem 0.6rem;
  }
}

/* ==========================================================================
   Root Home page (/drive/browse) — minimalist virtual-folder cards
   ========================================================================== */

/* Page wrapper — same pattern as .fh-search-container / .fh-storage-page: the
   layout's .fh-content well already supplies the page padding, gutter and
   shell cap, so the page owns only its vertical rhythm and a full-width cap. */
.fh-home-page {
  width: 100%;
  max-width: var(--fh-read-max);
  margin-inline: auto;
  min-width: 0;
}

.fh-home-page .fh-content-head-main .fh-page-header {
  flex: 0 1 auto;
}
.fh-home-page .fh-page-title {
  font-size: var(--fh-text-4xl);
  font-weight: var(--fh-weight-bold);
  letter-spacing: var(--fh-tracking-tighter);
}

/* .fh-content-head-main is a space-between flex row, so a bare <p> here lands
   opposite the title instead of beneath it. A 100% flex-basis forces its own
   line; source order keeps it above the toolbar row. */
.fh-page-subtitle {
  flex: 1 0 100%;
  order: 1;
  margin: 0.35rem 0 0;
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
}

/* Home glyph tile — primary blue rather than the folder-yellow default, so
   the launchpad reads as its own surface (same idea as
   .fh-page-title-icon-storage on the Storage pages). */
.fh-page-title-icon-home {
  background: rgba(37, 99, 235, 0.12);
  color: var(--fh-primary, #2563eb);
}

.fh-page-title-icon-search {
  background: rgba(139, 92, 246, 0.12);
  color: #8b5cf6;
}

.fh-page-title-icon-trash {
  background: rgba(100, 116, 139, 0.12);
  color: var(--fh-muted);
}

.fh-page-title-icon-shared {
  background: rgba(13, 148, 136, 0.12);
  color: #0d9488;
}

/* Recent page glyph tile — teal, matching the clock-rotate icon's "history"
   reading without colliding with Home's blue or Storage's darker blue. */
.fh-page-title-icon-recent {
  background: rgba(13, 148, 136, 0.12);
  color: #0d9488;
}

/* One clean cluster of top-level virtual folders. Only two render today
   (My Drive, Shared); Department/Company cards slot in with no page change.
   auto-fit (not auto-fill) collapses empty tracks, so the cards share the
   page cap instead of leaving phantom columns beside them on wide viewports. */
.fh-home-roots {
  display: grid;
  padding-inline: var(--fh-head-inset, 0);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
  gap: var(--fh-section-gap, 1.1rem);
}

@media (max-width: 767.98px) {
  .fh-home-roots {
    grid-template-columns: 1fr;
  }
}

.fh-home-card {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1.375rem 1.5rem;
  background: #ffffff;
  border: 1px solid var(--fh-border);
  border-radius: 1.125rem;
  color: var(--fh-text);
  text-decoration: none;
  box-shadow: none;
  transition: box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease,
              background-color 0.18s ease;
}

.fh-home-card:hover {
  border-color: var(--fh-primary-soft-border, #bfdbfe);
  background: var(--fh-primary-soft, #eff6ff);
  box-shadow: 0 6px 20px rgba(37, 99, 235, 0.08);
  transform: translateY(-2px);
  color: var(--fh-text);
}

/* Keyboard focus must be as obvious as hover — the cards are the page's only
   interactive elements. Same two-ring treatment as the app's buttons. */
.fh-home-card:focus-visible {
  outline: none;
  border-color: var(--fh-primary, #2563eb);
  box-shadow: 0 0 0 0.1rem var(--fh-focus-halo, #fff), 0 0 0 0.25rem #258cfb;
}

.fh-home-card:active {
  transform: translateY(1px);
  color: var(--fh-primary-dark);
  box-shadow: 0 4px 12px -2px rgba(37, 99, 235, 0.08);
}

/* Coarse pointers: the whole card is the tap target, so keep it comfortably
   above the 44px floor the rest of the touch UI uses. */
@media (pointer: coarse) {
  .fh-home-card {
    min-height: 4.5rem;
  }
}

.fh-home-card-icon {
  flex-shrink: 0;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 0.8125rem;
  background: var(--fh-soft);
  border: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fh-text-lg);
  color: var(--fh-primary);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

.fh-home-card:hover .fh-home-card-icon {
  transform: scale(1.05);
}

/* Per-kind icon tints, same idea as the browse grid's .fh-card-icon tiles —
   the two roots are distinguishable at a glance, and the reserved kinds
   already have a colour if the service ever returns them. */
.fh-home-card[data-kind="Personal"] .fh-home-card-icon {
  background: #eaf0fe;
  color: var(--fh-primary);
}
.fh-home-card[data-kind="Shared"] .fh-home-card-icon {
  background: #eaf0fe;
  color: var(--fh-primary);
}
.fh-home-card[data-kind="Department"] .fh-home-card-icon {
  background: #fef3c7;
  border-color: rgba(253, 230, 138, 0.7);
  color: #d97706;
}

.fh-home-card-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.fh-home-card-name {
  font-weight: var(--fh-weight-semibold);
  font-size: var(--fh-text-lg);
  letter-spacing: var(--fh-tracking-tight);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fh-home-card-arrow {
  flex-shrink: 0;
  margin-left: auto;
  color: var(--fh-muted);
  font-size: var(--fh-text-sm);
  transition: transform 0.18s ease, color 0.18s ease;
}

.fh-home-card:hover .fh-home-card-arrow {
  color: var(--fh-primary);
  transform: translateX(2px);
}

.fh-home-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem 1rem;
  margin-top: var(--fh-section-gap, 1.1rem);
  padding-inline: var(--fh-head-inset, 0);
}

.fh-home-section-title {
  margin: 0;
  font-size: var(--fh-text-xl);
  font-weight: var(--fh-weight-bold);
  letter-spacing: var(--fh-tracking-tight);
}

.fh-home-section-link {
  font-size: var(--fh-text-sm);
  font-weight: var(--fh-weight-medium);
  color: var(--fh-muted);
  text-decoration: none;
}

.fh-home-section-link:hover {
  color: var(--fh-primary);
}

.fh-home-recent-card {
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.fh-home-recent-meta {
  font-size: var(--fh-text-sm);
  color: var(--fh-muted);
  margin-top: 0.15rem;
}

/* Keycap — shortcuts modal. */
.fh-shortcut-list kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.6rem;
  padding: 0.12rem 0.4rem;
  background: var(--fh-soft);
  border: 1px solid var(--fh-border);
  border-bottom-width: 2px;
  border-radius: 0.375rem;
  color: var(--fh-text);
  font-family: var(--fh-font-sans);
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  line-height: var(--fh-leading-snug);
}

/* Shortcuts modal — one row per shortcut: keycaps left, action right. */
.fh-shortcut-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.fh-shortcut-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.fh-shortcut-keys {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--fh-muted);
  font-size: var(--fh-text-xs);
  white-space: nowrap;
}
.fh-shortcut-action {
  color: var(--fh-text);
  font-size: var(--fh-text-base);
  text-align: right;
}

@media (prefers-reduced-motion: reduce) {
  .fh-home-card,
  .fh-home-card-icon {
    transition: none;
  }
  .fh-home-card:active {
    transform: none;
  }
}

/* Permission badge — quiet pill reused on the Home root cards and on every
   item row/card of the /drive/shared listing. Level-coloured, low contrast so
   it reads as metadata, not a button. */
.fh-perm-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.12rem 0.55rem;
  border-radius: var(--bs-border-radius-pill, 50rem);
  font-size: var(--fh-text-xs);
  font-weight: var(--fh-weight-semibold);
  letter-spacing: var(--fh-tracking-wide);
  white-space: nowrap;
  border: 1px solid transparent;
}

.fh-perm-owner {
  color: #1d4ed8;
  background: #eff6ff;
  border-color: #bfdbfe;
}

.fh-perm-edit {
  color: #15803d;
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.fh-perm-view {
  color: #92400e;
  background: #fffbeb;
  border-color: #fde68a;
}

.fh-perm-noaccess {
  color: var(--fh-muted);
  background: var(--fh-soft);
  border-color: var(--fh-border);
}

/* Badge placed as a direct child of .fh-card (below the name) on the
   /drive/shared grid — pinned to the card's bottom edge, Drive-style. */
.fh-card > .fh-perm-badge {
  align-self: flex-start;
  margin-top: auto;
  padding-top: 0.25rem;
}

/* Admin Departments — compact list + detail */
.fh-dept-page {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 56rem;
}
.fh-dept-page .fh-content-head-main {
  gap: 0.75rem;
}
.fh-dept-search {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  background: var(--fh-soft);
  border: 1px solid var(--fh-border);
  border-radius: 0.5rem;
  padding: 0 0.6rem;
  min-width: 12rem;
}
.fh-dept-search i { color: var(--fh-muted); font-size: var(--fh-text-sm); }
.fh-dept-search .form-control {
  border: 0;
  background: transparent;
  box-shadow: none;
  padding-left: 0;
}
.fh-page-title-icon-dept {
  background: rgba(99, 102, 241, 0.12);
  color: #6366f1;
}
.fh-dept-name {
  font-weight: var(--fh-weight-semibold);
  color: var(--fh-text);
  text-decoration: none;
}
.fh-dept-name:hover { text-decoration: underline; }
.fh-dept-code,
.fh-dept-meta {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
}
.fh-dept-code-chip {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
  background: var(--fh-soft);
  border-radius: 999px;
  padding: 0.15rem 0.55rem;
}
.fh-dept-empty-chair {
  color: var(--fh-muted);
  font-size: var(--fh-text-sm);
}
.fh-dept-empty-chair i { margin-right: 0.25rem; }
.fh-dept-row-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.15rem;
}
.fh-dept-row-actions form { margin: 0; }
.fh-dept-row-actions a.fh-icon-btn { text-decoration: none; color: inherit; }
.fh-dept-row-actions .fh-icon-btn.disabled {
  opacity: 0.35;
  pointer-events: none;
}
.fh-dept-meter { min-width: 10rem; max-width: 16rem; }
.fh-storage-bar-compact {
  height: 0.4rem;
  border-radius: 999px;
}
.fh-storage-bar-caption {
  font-size: var(--fh-text-xs);
  margin-top: 0.2rem;
  line-height: var(--fh-leading-tight);
}
.fh-dept-sort {
  color: inherit;
  text-decoration: none;
}
.fh-dept-sort:hover { color: var(--fh-text); }
.fh-dept-sort.is-sorted { color: var(--fh-text); }
.fh-dept-section {
  padding-top: 0.25rem;
}
.fh-dept-section-title {
  font-size: var(--fh-text-base);
  font-weight: var(--fh-weight-semibold);
  margin-bottom: 0.75rem;
}
.fh-dept-section-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}
.fh-dept-form { max-width: 24rem; }
.fh-dept-inline-form {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: 28rem;
}
.fh-dept-inline-form .form-select { flex: 1; min-width: 0; }

/* Admin Users — same workspace as Departments, a bit wider for the extra columns */
.fh-users-page {
  max-width: 72rem;
}
.fh-page-title-icon-users {
  background: rgba(14, 165, 233, 0.12);
  color: #0ea5e9;
}
.fh-users-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
  min-width: 0;
}
.fh-users-filters .fh-dept-search {
  flex: 1 1 12rem;
  min-width: 10rem;
}
.fh-users-filters .form-select {
  width: auto;
  min-width: 8rem;
}
.fh-user-sub {
  font-size: var(--fh-text-xs);
  color: var(--fh-muted);
  line-height: var(--fh-leading-snug);
}
@media (max-width: 767.98px) {
  .fh-users-filters {
    flex-basis: 100%;
  }
  .fh-users-filters .form-select {
    flex: 1 1 8rem;
  }
}

