/**
 * Nav rail — collapsible left-side navigation, shared by two independent
 * rails that are never on screen at once (see dashboard-rail.js for the
 * state machine both instantiate against):
 *   #dashboardRail  the dashboard's 5 sections (Overview/Transactions/
 *                   Bookings/Fleet/Team), containing the #dashboardTabs
 *                   buttons (same ids, same onclick, same .active toggle
 *                   driven by switchDashboardTab() in main.js).
 *   #adminRail      the admin panel's 10 sections (User Roles/Social
 *                   Links/.../Backup), containing the #adminTabs buttons
 *                   (same ids, same onclick, same active-class toggle
 *                   driven by switchAdminTab() in admin.js).
 * Both share the .app-rail/.app-rail-scrim/.app-rail-edge-tab structural
 * classes and the state classes below, so this file only has to define
 * the positioning/animation once; only the two rails' own contents differ
 * (.dashboard-tab vs .admin-tab handle each nav's label/icon layout).
 *
 * States (see public/js/utils/dashboard-rail.js for the state machine):
 *   .rail-expanded       240px, icon + label, docked (pushes content)
 *   .rail-collapsed      68px,  icon only,    docked (pushes content)
 *   .rail-drawer-closed  off-canvas (<768px default)
 *   .rail-drawer-open    off-canvas, slid into view, with scrim
 *   .rail-flyout         temporary overlay on top of .rail-collapsed,
 *                        does NOT push content (see --rail-offset below)
 */

:root {
  --rail-offset: 0px;
}

.app-rail {
  position: fixed;
  top: 3.5rem; /* 56px, matches header's h-14 */
  left: 0;
  /* vh first as a fallback for browsers without dvh support, dvh second
     so it wins where available — 100vh is the LARGEST possible viewport
     (address bar hidden), so on a real phone with the address bar
     showing (the default state) a plain vh height runs taller than
     what's actually visible, pushing the footer/collapse-toggle below
     the fold until the user scrolls. dvh tracks the actual visible
     viewport instead, same fix already used for modal panels
     (responsive-primitives.css's 92dvh). */
  height: calc(100vh - 3.5rem);
  height: calc(100dvh - 3.5rem);
  z-index: 35; /* below header's z-40 and its dropdowns */
  display: flex;
  flex-direction: column;
  background: #0f172a;
  border-right: 1px solid rgba(51, 65, 85, 0.6);
  overflow: visible; /* lets .rail-flyout extend past the rail's own edge */
  transition: width 220ms cubic-bezier(0, 0, 0.2, 1),
              transform 220ms cubic-bezier(0, 0, 0.2, 1);
}
@media (min-width: 640px) {
  .app-rail {
    top: 4rem; /* 64px, matches header's sm:h-16 */
    height: calc(100vh - 4rem);
    height: calc(100dvh - 4rem);
  }
}
.app-rail.hidden {
  display: none;
}

/* ── Docked width states ──────────────────────────────────────────────── */
.app-rail.rail-expanded {
  width: 240px;
}
.app-rail.rail-collapsed {
  width: 68px;
}

/* <main>'s push offset — JS is the only thing that sets this value; <main>
   itself carries no per-state class.
   This used to be margin-left + a matching width:calc() shrink, but
   #mainContent's own margin-left is what custom.css's `main { max-width:
   1920px; margin: 0 auto }` rule depends on to center content on screens
   wider than 1920px — an ID selector always beats that plain-element
   selector, so this unconditionally pinned #mainContent's left edge at
   `--rail-offset` (0px on every page without the rail) instead of letting
   it center, leaving a permanent blank gap on the right on any display
   wider than 1920 logical px (a monitor at 2560/3440/4K, or just a
   zoomed-out browser — zooming out increases the effective CSS viewport
   width). Switched to padding-left instead, which reserves the same space
   for the rail without touching margin — box-sizing:border-box (global
   reset) means adding padding-left shrinks the *content* area on the left
   only, leaving the box's own outer width/position (and hence `main`'s
   centering) alone, so there's also no separate need to shrink width to
   keep the rail from pushing the right edge past the viewport.
   The five rules below reproduce #mainContent's own responsive left
   gutter — now defined in custom.css as a smaller app-wide scale (0.625rem
   through 1.5rem, replacing the original px-3 sm:px-4 lg:px-6 xl:px-10
   2xl:px-16 Tailwind classes) — at the same breakpoints/values so the rail
   offset is added on top of the current gutter instead of a stale one;
   this ID selector otherwise beats that rule (same specificity, loads
   later) and would leave a mismatched gutter behind whenever the values
   here drift out of sync with custom.css's. */
#mainContent {
  padding-left: calc(0.625rem + var(--rail-offset, 0px));
  transition: padding-left 220ms cubic-bezier(0, 0, 0.2, 1);
}
@media (min-width: 640px) {
  #mainContent { padding-left: calc(0.75rem + var(--rail-offset, 0px)); }
}
@media (min-width: 1024px) {
  #mainContent { padding-left: calc(1rem + var(--rail-offset, 0px)); }
}
@media (min-width: 1280px) {
  #mainContent { padding-left: calc(1.25rem + var(--rail-offset, 0px)); }
}
@media (min-width: 1536px) {
  #mainContent { padding-left: calc(1.5rem + var(--rail-offset, 0px)); }
}

/* #adminPanelPage is the admin rail's equivalent push target — it lives
   outside <main> (see admin.js's openAdminPanel()) and already manages its
   own gutters per-panel (each #adminPanel* tab carries its own p-4 sm:p-6),
   so unlike #mainContent above it doesn't need a responsive base gutter
   stacked on top — just the rail offset itself, applied once here so it
   pushes every tab panel over without touching any of their own markup. */
#adminPanelPage {
  padding-left: var(--rail-offset, 0px);
  transition: padding-left 220ms cubic-bezier(0, 0, 0.2, 1);
}

/* ── Mobile off-canvas drawer (<768px) ────────────────────────────────── */
.app-rail.rail-drawer-closed {
  width: 240px;
  transform: translateX(-100%);
}
.app-rail.rail-drawer-open {
  width: 240px;
  transform: translateX(0);
  box-shadow: 4px 0 24px rgba(0, 0, 0, 0.4);
}

/* ── Fully-hidden state, desktop/tablet (>=768px) ─────────────────────────
   A third state beyond expanded/collapsed, reached only via the edge tab
   (.app-rail-edge-tab below) — slides fully off-canvas using the same
   translateX(-100%) language as the mobile drawer's closed state, for
   maximum content width when a user wants it. The push target's own
   --rail-offset is set to 0px for this state (dashboard-rail.js), same
   as when the rail isn't active at all, so content reclaims the full
   width instead of leaving a gap for a rail that isn't there. */
.app-rail.rail-fully-hidden {
  /* Explicit width (matching .rail-expanded), not the flex content's own
     auto width — without it, width and transform would animate
     SIMULTANEOUSLY during the hide/show transition (the base rule
     transitions both), since translateX(-100%) resolves against
     whatever width is current at each frame. Fixing the width here means
     only transform actually animates, the same single-property motion
     the mobile drawer's closed/open pair already uses. */
  width: 240px;
  transform: translateX(-100%);
  box-shadow: none;
}
.app-rail-scrim {
  position: fixed;
  inset: 0;
  top: 3.5rem;
  background: rgba(0, 0, 0, 0.6);
  z-index: 34; /* just below the rail so the rail itself stays clickable */
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms cubic-bezier(0, 0, 0.2, 1);
}
@media (min-width: 640px) {
  .app-rail-scrim { top: 4rem; }
}
.app-rail-scrim.visible {
  opacity: 1;
  pointer-events: auto;
}

/* ── Edge tab: opens/closes its associated rail ───────────────────────────
   Fixed to the viewport's own left edge (not the rail's), so it's always
   reachable regardless of the rail's current state (expanded/collapsed/
   fully-hidden/mobile-drawer-closed) — a few px inset from the true edge
   rather than flush, using calc() with env(safe-area-inset-left) so a
   device with a curved/rounded screen edge or a landscape notch on this
   side doesn't clip it (falls back to just the base inset via the 0px
   default when the device reports no inset at all).
     Vertically anchored in the lower-middle third of the viewport
   (top: 62%, not pinned to the top) so it's reachable by a thumb during
   one-handed phone use, clear of both a status bar/notch above and
   Android's own gesture nav bar below. position:fixed with a % top
   resolves against the viewport itself, so this stays correctly placed
   through scroll and through a mobile browser's own address-bar show/
   hide without needing dvh.
     44x44px hit target (WCAG minimum) even though the visible pill
   (the ::before pseudo-element) is narrower — tap accuracy shouldn't
   depend on hitting a slim graphic exactly. Tap/click only, no drag-
   from-edge gesture: swiping in from the left edge is Android's own
   system back-gesture zone, and a custom edge-swipe handler here would
   directly conflict with it on real devices (confirmed against a
   Samsung Galaxy S23 viewport — see the note on MOBILE_BREAKPOINT-scoped
   behavior in dashboard-rail.js). Both rails' edge tabs share this exact
   spot since only one of the two is ever unhidden at a time. */
.app-rail-edge-tab {
  position: fixed;
  top: 62%;
  left: calc(4px + env(safe-area-inset-left, 0px));
  transform: translateY(-50%);
  z-index: 45; /* above the rail (35) and its scrim (34) — always reachable */
  width: 44px;
  height: 44px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.app-rail-edge-tab.hidden {
  display: none;
}
/* The visible pill — a rounded tab attached to the edge, narrower than
   the 44px hit box above and centered within it. */
.app-rail-edge-tab::before {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 26px;
  height: 52px;
  border-radius: 0 999px 999px 0;
  background: linear-gradient(160deg, #1e293b, #0f172a);
  border: 1px solid rgba(100, 116, 139, 0.5);
  border-left: none;
  box-shadow: 2px 0 12px rgba(0, 0, 0, 0.35);
  transition: box-shadow 200ms ease, border-color 200ms ease;
}
.app-rail-edge-tab i {
  position: relative;
  z-index: 1;
  color: var(--accent);
  font-size: 12px;
  transition: transform 220ms cubic-bezier(0, 0, 0.2, 1), color 200ms ease;
}
.app-rail-edge-tab:hover::before,
.app-rail-edge-tab:focus-visible::before {
  border-color: rgba(var(--accent-rgb), 0.55);
  box-shadow: 0 0 12px rgba(var(--accent-rgb), 0.35), 2px 0 12px rgba(0, 0, 0, 0.35);
}
.app-rail-edge-tab:focus-visible {
  outline: var(--focus-ring-width) solid var(--accent);
  outline-offset: 2px;
  border-radius: 0 999px 999px 0;
}
/* Admin rail's edge tab — same shape/motion/hit-target as the dashboard's,
   just recolored to the admin panel's amber identity (matching
   .rail-header-icon--amber and the active-tab accent already used
   throughout #adminRail) instead of the site's default cyan --accent. */
.app-rail-edge-tab--amber i {
  color: #f59e0b;
}
.app-rail-edge-tab--amber:hover::before,
.app-rail-edge-tab--amber:focus-visible::before {
  border-color: rgba(245, 158, 11, 0.55);
  box-shadow: 0 0 12px rgba(245, 158, 11, 0.35), 2px 0 12px rgba(0, 0, 0, 0.35);
}
.app-rail-edge-tab--amber:focus-visible {
  outline-color: #f59e0b;
}
/* Open state: chevron flips to point back toward the edge it opened
   from, the same rotation language the app already uses for other
   expand/collapse affordances (the FAQ accordion chevron, the rail's own
   pin button icon swap). */
.app-rail-edge-tab[aria-expanded="true"] i {
  transform: rotate(180deg);
}

/* ── Hover/focus flyout while collapsed (desktop/tablet only) ────────────
   Layered overlay — widens the rail visually without ever touching
   --rail-offset, so the content pane never reflows during a flyout peek. */
.app-rail.rail-collapsed.rail-flyout {
  width: 240px;
  box-shadow: 4px 0 24px rgba(0, 0, 0, 0.5);
}

/* ── Rail chrome ───────────────────────────────────────────────────────── */
/* Identity header — icon + section name, pinned to the top of the rail.
   Doubles as the admin rail's replacement for the old full-width "Admin
   Panel" title bar (removed from #adminPanelPage entirely): same icon and
   color as that page's Quick Access entry (see custom.css's
   #adminHeaderButton), just living inside the rail instead of its own
   edge-to-edge row, so opening the panel no longer spends a whole extra
   header's worth of vertical space on it. The dashboard rail gets the
   same treatment for a consistent "sidebar app" feel between both rails,
   using its own Quick Access entry's icon (#adminDashboardIcon). */
.rail-header {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  /* Matches the nav items' own 0.625rem/0.75rem padding below — this used
     to run noticeably taller (0.875rem vertical + a 36px icon) than
     everything else in the rail, on both mobile and desktop. */
  padding: 0.625rem 0.75rem;
  flex-shrink: 0;
  border-bottom: 1px solid rgba(51, 65, 85, 0.5);
  overflow: hidden;
}
.rail-header-icon {
  width: 2rem;
  height: 2rem;
  border-radius: 0.625rem;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 0.8125rem;
}
.rail-header-icon--cyan {
  background: rgba(34, 211, 238, 0.1);
  border: 1px solid rgba(34, 211, 238, 0.2);
  color: #22d3ee;
}
.rail-header-icon--amber {
  background: rgba(245, 158, 11, 0.1);
  border: 1px solid rgba(245, 158, 11, 0.2);
  color: #f59e0b;
}
.rail-header-label {
  color: #fff;
  font-size: 0.9375rem;
  font-weight: 800;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 1;
  transition: opacity 150ms ease;
}
/* Collapsed (icon-only) — same label-hiding treatment as the nav items
   below, so the header shrinks down to just its icon, centered. */
.rail-collapsed .rail-header {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}
.rail-collapsed .rail-header-label {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
  opacity: 0;
}
/* Flyout peek (hover/focus while collapsed) reveals the header label again,
   same as the nav items below it — the whole rail widens together. */
.rail-collapsed.rail-flyout .rail-header {
  justify-content: flex-start;
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}
.rail-collapsed.rail-flyout .rail-header-label {
  position: static;
  width: auto; height: auto;
  padding: 0; margin: 0;
  clip: auto;
  opacity: 1;
}

.rail-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0.75rem;
  flex-shrink: 0;
  border-top: 1px solid rgba(51, 65, 85, 0.5);
}
/* Bare icon, no background box on hover either — same "no circle/
   rectangle behind the icon" treatment as .btn-close/.btn-icon-danger. */
.rail-pin-btn {
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #94a3b8;
  background: transparent;
  transition: color 0.2s ease;
  flex-shrink: 0;
}
.rail-pin-btn:hover {
  color: #22d3ee;
}

.rail-nav {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

/* ── Nav items — replaces .dashboard-tab's old horizontal-pill look.
   Same class names as before (.dashboard-tab / .dashboard-tab.active),
   same active-toggle contract in switchDashboardTab() — CSS-only change. */
.dashboard-tab {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  text-align: left;
  gap: 0.875rem;
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 0.625rem 0.75rem;
  border-radius: 0.625rem;
  color: #94a3b8;
  background: transparent;
  border: none;
  border-left: 3px solid transparent;
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
  transition: all 0.2s ease;
  position: relative;
}
/* Hover reuses the same cyan accent as .active's left-border/background
   below (just lighter/softer, same relationship as the admin rail's own
   text-amber-300 hover vs. text-amber-400 active) — previously a plain
   grey with no accent at all, so hovering here gave no color feedback the
   way the admin rail's amber hover already did. */
.dashboard-tab:hover {
  color: #67e8f9;
  background: rgba(34, 211, 238, 0.08);
}
/* Active text/icon match the border-left color exactly (same relationship
   as the admin rail's text-amber-400 + border-amber-400) — previously
   white, which read as "selected" via the background tint alone but never
   colored the icon itself, so a COLLAPSED (icon-only) active tab showed a
   plain white icon instead of the cyan accent every other state already
   uses. */
.dashboard-tab.active {
  color: #22d3ee;
  background: rgba(34, 211, 238, 0.12);
  border-left-color: #22d3ee;
}
.dashboard-tab i {
  width: 1.125rem;
  text-align: center;
  flex-shrink: 0;
  font-size: 0.9375rem;
}
.dashboard-tab span {
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 1;
  transition: opacity 150ms ease;
}

/* Collapsed (icon-only) — hide labels, center the icon; flyout/expanded/
   drawer states all override this back to visible below. */
.rail-collapsed .dashboard-tab span {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
  opacity: 0;
}
.rail-collapsed .dashboard-tab {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}
.rail-collapsed.rail-flyout .dashboard-tab span {
  position: static;
  width: auto; height: auto;
  padding: 0; margin: 0;
  clip: auto;
  opacity: 1;
}
.rail-collapsed.rail-flyout .dashboard-tab {
  justify-content: flex-start;
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

/* ── Admin rail's nav items ────────────────────────────────────────────
   Layout-only counterpart to .dashboard-tab above — the admin buttons
   keep every one of their existing Tailwind classes (border-l-4,
   bg-slate-700/60, text-amber-400, etc.), since switchAdminTab() in
   admin.js toggles active/inactive state through those classes directly
   rather than a single semantic .active class. This rule supplies what
   Tailwind's inline-block markup didn't have — a flex row for the
   icon+label gap, the same label-collapse/flyout behavior as the
   dashboard rail — and mirrors .dashboard-tab's own gap/alignment/
   border-radius values exactly (rather than the old pill-bar's own
   px-4 py-3/rounded-lg, now dropped from the HTML classes below) so the
   two rails' items line up and read as one consistent component, not
   two differently-proportioned ones. Colors, hover, active-state and the
   border-left accent are untouched and keep working exactly as before. */
.admin-tab {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  text-align: left;
  gap: 0.875rem;
  width: 100%;
  box-sizing: border-box;
  border-radius: 0.625rem;
  position: relative;
}
.admin-tab i {
  width: 1.125rem;
  text-align: center;
  flex-shrink: 0;
}
.admin-tab span {
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 1;
  transition: opacity 150ms ease;
}
.rail-collapsed .admin-tab span {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
  opacity: 0;
}
.rail-collapsed .admin-tab {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}
.rail-collapsed.rail-flyout .admin-tab span {
  position: static;
  width: auto; height: auto;
  padding: 0; margin: 0;
  clip: auto;
  opacity: 1;
}
.rail-collapsed.rail-flyout .admin-tab {
  justify-content: flex-start;
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

/* ── Collapsed-state tooltips — nav items reuse the app's one canonical
   [data-tooltip] component (see custom.css) rather than a bespoke rail-only
   implementation; each button already carries data-tooltip+
   data-tooltip-pos="right" in index.html. Only suppress it while expanded/
   flyout/mobile-drawer, since the label is already visible as text there —
   showing a tooltip with the same words right next to it would be
   redundant clutter, not "necessary". Applies to both rails' nav items. ──*/
.rail-expanded .dashboard-tab[data-tooltip]::after,
.rail-expanded .dashboard-tab[data-tooltip]::before,
.rail-flyout .dashboard-tab[data-tooltip]::after,
.rail-flyout .dashboard-tab[data-tooltip]::before,
.rail-drawer-open .dashboard-tab[data-tooltip]::after,
.rail-drawer-open .dashboard-tab[data-tooltip]::before,
.rail-drawer-closed .dashboard-tab[data-tooltip]::after,
.rail-drawer-closed .dashboard-tab[data-tooltip]::before,
.rail-expanded .admin-tab[data-tooltip]::after,
.rail-expanded .admin-tab[data-tooltip]::before,
.rail-flyout .admin-tab[data-tooltip]::after,
.rail-flyout .admin-tab[data-tooltip]::before,
.rail-drawer-open .admin-tab[data-tooltip]::after,
.rail-drawer-open .admin-tab[data-tooltip]::before,
.rail-drawer-closed .admin-tab[data-tooltip]::after,
.rail-drawer-closed .admin-tab[data-tooltip]::before {
  display: none;
}

/* ── Responsive: rail hides entirely below 768px unless explicitly the
   mobile drawer state (rail-drawer-open/closed apply their own transform,
   see above) — 768 matches MOBILE_BREAKPOINT in dashboard-rail.js; keep
   the two in sync if that constant ever changes ─────────────────────── */
@media (max-width: 767px) {
  .app-rail.rail-expanded,
  .app-rail.rail-collapsed {
    /* Below 768px the JS state machine only ever applies
       rail-drawer-open/closed, but this is a defensive fallback. */
    transform: translateX(-100%);
  }
}
