/* =========================================================================
   Sidebar navigation
   -------------------------------------------------------------------------
   EXTENSION to the design system, not a mirror of it. Mockup 6a's
   "Tabs & navigation" specifies underline tabs, pill nav, breadcrumbs and
   pagination — there is no sidebar anywhere in the mockups. Everything here is
   therefore DERIVED from DS primitives that do exist:

     · the pill active state from 6a's nav row (mist fill, green-700 text)
     · the ink ramp for resting/hover text
     · --brand-strong wherever green carries body-size text (green-500 on
       white is 3.08:1 and fails AA)
     · Lucide icons, Poppins, DS radii, shadows and easing

   Recorded as PROPOSED in KRAYIN-RECONCILIATION.md, pending ratification.

   Owner: design-system-agent
   ========================================================================= */

:root {
  --nav-w: 248px;
  --nav-rail: 68px;
  --nav-row-h: 38px;

  /* ─────────────────────────────────────────────────────────────────────────
     THE ADMIN HEADER'S HEIGHT, AS A TOKEN, FOR THE FIRST TIME.
     ─────────────────────────────────────────────────────────────────────────

     `60px` is hardcoded as a Tailwind arbitrary value in more than seventy
     places across the admin — `top-[60px]`, `h-[60px]`, `mt-[60px]` — and there
     has never been a custom property for it. Anything that needs to sit BELOW
     the header (a sticky column, a full-height rail, a bottom bar computing
     `100dvh - header`) therefore had a choice between a seventy-first literal
     and inventing a token.

     This is that token. It is deliberately introduced alongside --nav-w and
     --nav-rail, the shell's other two structural measurements, and its value is
     the measured one rather than a new decision — nothing moves by adding it.

     NOT a retrofit of the seventy: rewriting live Tailwind classes across the
     admin is a separate change with its own risk, and doing it as a side effect
     of a filter-panel task is how unrelated regressions get attributed to the
     wrong commit. New code reads the token; the literals stay until somebody
     owns that sweep.

     Owner for ratification: design-system-agent / crm-design-tokens-engineer. */
  --shell-header-h: 60px;

  /* Gap between the rail's edge and the page content. */
  --nav-gutter: var(--space-4);

  /* ONE timing for the rail and the page, so they move as a single gesture.
     They previously ran 200ms and 300ms, which reads as the content chasing
     the sidebar rather than travelling with it. */
  --nav-motion: var(--dur-base) var(--ease);
}

/* ------------------------------------------------------- rail + content -- */

/**
 * The sidebar is position:fixed, so the page cannot flow around it — content
 * has to reserve the space itself. Both sides derive from the SAME two
 * variables here; before this they were three hardcoded pixel values in two
 * files, which silently desynced when the rail was rewidened and left 33px of
 * every page sitting underneath the sidebar.
 *
 * Scoped to >=1024px because the desktop rail is `max-lg:hidden` — below that
 * the mobile drawer takes over and content must not reserve anything.
 */
#admin-sidebar {
  width: var(--nav-w);
  transition: width var(--nav-motion);
}

.sidebar-collapsed #admin-sidebar {
  width: var(--nav-rail);
}

@media (min-width: 1024px) {
  .nav-offset {
    padding-inline-start: calc(var(--nav-w) + var(--nav-gutter));
    transition: padding-inline-start var(--nav-motion);
  }

  .sidebar-collapsed .nav-offset {
    padding-inline-start: calc(var(--nav-rail) + var(--nav-gutter));
  }
}

/* padding-inline-start handles RTL on its own, so the mirrored rule the
   Tailwind version needed is gone — but the fixed rail still has to flip. */
[dir="rtl"] #admin-sidebar {
  left: auto;
  right: 0;
}

/* ------------------------------------------------------------------ shell -- */

.nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  height: 100%;
  padding: var(--space-3) 0 var(--space-4);
  font-family: var(--font-body);
}

/* The scroll region holds the groups; the footer group is pushed to the
   bottom so Settings/Help sit against the base of the rail on tall screens
   without being fixed and overlapping content on short ones. */
.nav__scroll {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-1);
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: thin;
  /* Task #47 item 2. scrollbar-width alone leaves the thumb/track colour to
     the UA, which follows the OS theme rather than this page's .dark class
     (tokens.css now also sets color-scheme on :root/.dark as the ancestor-
     level fix; this is the explicit colour so the thumb matches the token
     system exactly rather than the browser's generic dark grey).
     --ui-subtle is the token already reserved for non-text foregrounds and
     is unchanged in light (ink-400 on white, 3.14:1 — see the --fg-/--ui-
     namespace note above) and in dark (ink-500 on --bg, 3.11:1 — ratified in
     DARK-MODE-RULINGS.md D2). Track is transparent in both modes so no new
     surface is introduced. */
  scrollbar-color: var(--ui-subtle) transparent;
}

.nav__group--footer {
  margin-top: auto;
  padding-top: var(--space-2);
}

.nav__group + .nav__group--footer {
  border-top: 1px solid var(--divider);
}

.nav__eyebrow {
  margin: var(--space-3) 0 var(--space-1);
  padding: 0 var(--space-5);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--fg-subtle);
  white-space: nowrap;
}

/* -------------------------------------------------------------------- row -- */

.nav__item {
  position: relative;
  padding: 0 var(--space-3);
}

.nav__link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: var(--nav-row-h);
  padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--fg);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

/* THE RAIL'S ONE NON-NAVIGATING ROW — the Phone (design ruling A6, amended
   2026-09-17) — is a <button> rather than an <a>, because activating it opens
   the phone window and must not navigate the CRM tab.

   Two declarations, and only because Tailwind's preflight does not cover
   them. Preflight already gives a button a transparent background, no border,
   the inherited font and `cursor: pointer`, so .nav__link styles it exactly
   like its anchor siblings EXCEPT for two UA defaults that would make this
   one row look unlike the others: a button is shrink-to-fit, so its hover
   fill and its focus ring would stop at the word instead of spanning the row,
   and it centres its text, which .nav__link's flex layout passes straight
   down to .nav__label. Nothing else here changed for it. */
button.nav__link {
  width: 100%;
  text-align: start;
}

.nav__link:hover {
  background: var(--mist);
  color: var(--fg-strong);
}

.nav__link:focus-visible {
  outline: 2px solid var(--focus-outline, #00763d);
  outline-offset: -2px;
}

/* Active state is 6a's nav pill: mist fill, green-700 label. Deliberately NOT
   a solid brand fill — a saturated block on every page view is loud, and white
   on green-500 fails AA at this text size anyway. */
.nav__link[aria-current] {
  background: var(--mist);
  color: var(--brand-strong);
  font-weight: 600;
}

/* A 3px spine on the active row so the current section survives greyscale,
   forced-colors and colour-vision differences — the fill alone would not. */
.nav__link[aria-current]::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 3px;
  height: 20px;
  border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
  background: var(--brand-strong);
  transform: translateY(-50%);
}

/* Scoped to #admin-sidebar (not bare `.nav__icon`, unlike the rest of this
   file's class names): the icons task (KRAYIN-RECONCILIATION.md) put a
   `nav__icon` MARKER class on the mobile drawer's icon span too, purely so
   the generated icons.css rail-scoped rules (`.nav__icon.icon-x`) can find
   it there. That span keeps its own `text-2xl` sizing and inherited text
   colour; it must not also pick up the desktop rail's fixed 18px box and
   muted colour, which is what a bare `.nav__icon {}` rule here would do. */
#admin-sidebar .nav__icon {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--fg-muted);
}

/* Scoped to #admin-sidebar to match the base rule above: that rule's ID
   specificity (1,1,0) would otherwise outrank this override's (0,3,0)
   regardless of source order, leaving the glyph stuck at --fg-muted on
   hover and on the current row (fix round 1, review of ba7604b4). The
   mobile drawer sits outside #admin-sidebar, so it is unaffected either
   way - it never had a hover/current state to begin with. */
#admin-sidebar .nav__link:hover .nav__icon,
#admin-sidebar .nav__link[aria-current] .nav__icon {
  color: currentColor;
}

.nav__label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* THE COUNT PILL, AND SINCE 2026-09-14 IT HAS A RENDERER.
   It was a port of the design system's nav row with nothing in the product
   emitting it. Mail spec 1.4's sidebar badge is that renderer: a
   `<span class="nav__count">` grafted after `.nav__label` of the Mail row by
   `assets/js/mail-unread-badge.js` (pushed by
   `theme::admin.mail.unread-badge`), because core's sidebar has no badge slot
   and `packages/Webkul/Admin` is read-only.

   NOTHING HERE CHANGED FOR IT, deliberately - not a declaration, not a
   selector. The position (`flex: none` after the `flex: 1` label, before the
   caret), the `[aria-current]` variant below, and the collapsed-rail rules at
   :335 and :393 are what that graft paints with, unmodified. The number is
   `aria-hidden` and its unit is an `.sr-only` sibling inside this node, so the
   row announces "Mail, 12 unread" - M13's recipe for the folder pane's own
   counts, and the reason there is no `aria-label` on a generic span here. */
.nav__count {
  flex: none;
  min-width: 20px;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: var(--ink-100);
  font-size: 10.5px;
  font-weight: 700;
  color: var(--ink-600);
  text-align: center;
}

.nav__link[aria-current] .nav__count {
  background: var(--brand-soft);
  color: var(--green-800);
}

.nav__caret {
  flex: none;
  width: 14px;
  height: 14px;
  color: var(--fg-subtle);
  transition: transform var(--dur-fast) var(--ease);
}

.nav__item[data-open="true"] .nav__caret {
  transform: rotate(90deg);
}

/* ---------------------------------------------------------------- submenu -- */

.nav__sub {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 2px 0 var(--space-2);
  padding-left: 30px;
}

.nav__sub-link {
  display: block;
  padding: 6px var(--space-3);
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  color: var(--fg-muted);
  text-decoration: none;
  white-space: nowrap;
}

.nav__sub-link:hover {
  background: var(--mist);
  color: var(--fg-strong);
}

.nav__sub-link:focus-visible {
  outline: 2px solid var(--focus-outline, #00763d);
  outline-offset: -2px;
}

.nav__sub-link[aria-current] {
  color: var(--brand-strong);
  font-weight: 600;
}

/* ------------------------------------------------------------- collapsed -- */

/* Collapsed, the rail shows icons only. Labels are not `display:none` —
   they stay in the accessibility tree and are revealed by the hover/focus
   expansion below. */
/**
 * The scroll container must stop clipping once collapsed, or the hover
 * expansion is cropped at the 68px rail edge. CSS does not allow
 * `overflow-x: visible` alongside `overflow-y: auto` — specifying one
 * non-visible axis forces the other to auto — so the whole property goes
 * visible on the rail. Safe here: the rail holds ten icon rows, which do not
 * scroll at any realistic viewport. Krayin's stock sidebar resolves the same
 * conflict the same way.
 */
.sidebar-collapsed .nav__scroll {
  overflow: visible;
}

/* Collapsed, the group heading goes entirely — not to a hairline. Keeping any
   box for it left uneven gaps between icons, so the rail read as a set of
   clusters rather than one evenly-spaced column. The grouping is still there
   the moment the rail expands. */
.sidebar-collapsed .nav__eyebrow {
  display: none;
}

/* Groups stop contributing their own spacing too, so every icon sits the same
   distance from the next regardless of which group it belongs to. The flex gap
   goes as well — 4px per boundary was still enough to read as a break. */
.sidebar-collapsed .nav__group,
.sidebar-collapsed .nav__group--footer {
  padding-top: 0;
  border-top: none;
}

.sidebar-collapsed .nav__scroll {
  gap: 0;
}

.sidebar-collapsed .nav__link {
  gap: 0;
  padding: 0;
  justify-content: center;
}

.sidebar-collapsed .nav__label,
.sidebar-collapsed .nav__count,
.sidebar-collapsed .nav__caret,
.sidebar-collapsed .nav__sub {
  display: none;
}

/**
 * THE HOVER EXPANSION.
 *
 * On the collapsed rail, hovering or focusing a single row expands THAT ROW
 * ONLY into a floating panel that grows out of the rail — the rest of the
 * sidebar does not move, and the page does not reflow.
 *
 * It is an absolutely-positioned overlay, so animating its width costs layout
 * on this element alone and never on the document. Opacity is staged behind the
 * width so the label fades in after there is room for it, rather than
 * reflowing mid-transition.
 *
 * :focus-within, not just :hover — a hover-only flyout is unreachable by
 * keyboard, which is the defect in Krayin's stock sidebar.
 */
.sidebar-collapsed .nav__item:hover,
.sidebar-collapsed .nav__item:focus-within {
  z-index: 30;
}

.sidebar-collapsed .nav__item:hover .nav__link,
.sidebar-collapsed .nav__item:focus-within .nav__link {
  position: absolute;
  top: 0;
  left: var(--space-3);
  z-index: 31;
  width: calc(var(--nav-w) - var(--space-6));
  padding: 0 var(--space-3);
  gap: var(--space-3);
  justify-content: flex-start;
  background: var(--bg);
  box-shadow: var(--shadow-md);
  /* No width transition here, deliberately. The row switches from static to
     absolute on hover, and `position` is not animatable — it changes
     discretely, leaving a width interpolation with no stable start value, so
     it bought no smoothness while still costing layout on this subtree.
     The reveal is carried by navReveal below (opacity + translate), which the
     compositor handles without touching layout at all. */
}

.sidebar-collapsed .nav__item:hover .nav__link[aria-current],
.sidebar-collapsed .nav__item:focus-within .nav__link[aria-current] {
  background: var(--mist);
}

/* The whole panel animates, not just its text, so the row still reads as
   growing out of the rail — achieved with transform/opacity rather than width,
   so nothing here triggers layout. */
.sidebar-collapsed .nav__item:hover .nav__link,
.sidebar-collapsed .nav__item:focus-within .nav__link {
  animation: navReveal var(--dur-base) var(--ease) both;
  transform-origin: left center;
}

.sidebar-collapsed .nav__item:hover .nav__label,
.sidebar-collapsed .nav__item:focus-within .nav__label,
.sidebar-collapsed .nav__item:hover .nav__count,
.sidebar-collapsed .nav__item:focus-within .nav__count {
  display: block;
}

/* A parent's children ride along in the same expansion, anchored under the
   row, so one hover reveals the whole branch instead of a second interaction. */
.sidebar-collapsed .nav__item:hover .nav__sub,
.sidebar-collapsed .nav__item:focus-within .nav__sub {
  display: flex;
  position: absolute;
  top: var(--nav-row-h);
  left: var(--space-3);
  z-index: 31;
  width: calc(var(--nav-w) - var(--space-6));
  margin: 0;
  padding: var(--space-2) var(--space-2) var(--space-2) 30px;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  background: var(--bg);
  box-shadow: var(--shadow-md);
  animation: navReveal var(--dur-base) var(--ease) both;
}

@keyframes navReveal {
  from { opacity: 0; transform: translateX(-4px); }
  to   { opacity: 1; transform: none; }
}

/* ----------------------------------------------------------------- brand -- */

/* Holds the collapse control only; the wordmark is in the app header above. */
.nav__brand {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  height: 36px;
  padding: 0 var(--space-4);
  margin-bottom: var(--space-1);
}

/* Circular brand button. --brand-strong, not --brand: the chevron is white and
   green-500 would put it at 3.08:1 — fine for a decorative shape, short of the
   3:1 UI-component bar once you account for the icon's thin strokes. */
.nav__toggle {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  margin-left: auto;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--brand-strong);
  color: var(--fg-on-brand);
  cursor: pointer;
  box-shadow: var(--shadow-xs);
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}

.nav__toggle:hover {
  background: var(--brand-strong-hover);
}

.nav__toggle:active {
  transform: translateY(1px);
}

.nav__toggle:focus-visible {
  outline: 2px solid var(--focus-outline, #00763d);
  outline-offset: 2px;
}

.nav__toggle-icon {
  width: 16px;
  height: 16px;
  transition: transform var(--dur-base) var(--ease);
}

.sidebar-collapsed .nav__toggle-icon {
  transform: rotate(180deg);
}

.sidebar-collapsed .nav__brand {
  padding: 0;
  justify-content: center;
}

/* tokens.css already neutralises animation globally under reduced motion; the
   transitions are named here too so the intent is explicit at the source. */
@media (prefers-reduced-motion: reduce) {
  .nav__link,
  .nav__caret,
  .nav__toggle-icon,
  .sidebar-collapsed .nav__item:hover .nav__link,
  .sidebar-collapsed .nav__item:focus-within .nav__link {
    transition: none;
  }
}
