/* ==========================================================================
   Side Navigation — a single rail that widens

   One element, two widths. Collapsed it is a 64px strip of icons; open it is
   240px with the labels showing. The rows do not move between the two, because
   the gutter is sized so that a collapsed row is a square with its icon on the
   rail's centre line.

   Open is driven by the `sidenav--open` class the controller sets on pointer
   enter, with `:hover` alongside it so the rail still works on a screen that
   loaded no JavaScript, and `:focus-within` so that tabbing in opens it too —
   a keyboard should not be left reading a column of unlabelled icons.
   `sidenav--pinned` is open that stays.

   Two themes. Everything below draws its colour from the rail's own custom
   properties, so a theme is the one block that redefines them and nothing else
   has to know which is on. Green is the default; `sidenav--dark` is the navy.
   ========================================================================== */
.sidenav {
  /* --- Green (default) --- */
  --rail-surface: var(--color-primary-green);
  /* Deepening towards the floor, so a full-height column of one colour does not
     read as a flat slab. */
  --rail-surface-deep: #46bd90;
  --rail-ink: var(--color-white);
  --rail-ink-soft: rgba(255, 255, 255, 0.75);
  --rail-hover: var(--tint-white-16);
  --rail-active: var(--tint-white-24);
  --rail-line: var(--tint-white-16);
  --rail-marker: var(--color-white);
  --rail-edge: var(--tint-navy-10);
  --rail-focus: 0 0 0 3px rgba(255, 255, 255, 0.5);
  --rail-scrollbar: var(--tint-white-24);

  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: var(--sidenav-width-collapsed);
  z-index: var(--z-sidenav);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: linear-gradient(
    180deg,
    var(--rail-surface) 0%,
    var(--rail-surface-deep) 100%
  );
  border-right: 1px solid var(--rail-edge);
  color: var(--rail-ink);
  transition: width var(--transition-slow), box-shadow var(--transition-slow),
    background var(--transition-base);
}

/* --- Navy (dark mode) ----------------------------------------------------- */
/* The rail becomes the left arm of the dark frame the top bar starts: same navy,
   flush to it. White has more room to work here than it does on green, so the
   ink can carry the hierarchy that the green theme puts into the fills. */
.sidenav--dark {
  --rail-surface: var(--color-primary-dark);
  --rail-surface-deep: #1b2c3e;
  --rail-ink: rgba(255, 255, 255, 0.92);
  --rail-ink-soft: rgba(255, 255, 255, 0.55);
  --rail-hover: rgba(255, 255, 255, 0.06);
  --rail-active: var(--tint-white-10);
  --rail-line: var(--tint-white-10);
  --rail-marker: var(--color-primary-green);
  --rail-edge: var(--tint-white-10);
  --rail-focus: 0 0 0 3px var(--tint-green-28);
}

.sidenav:is(:hover, :focus-within, .sidenav--open) {
  width: var(--sidenav-width-expanded);
  /* Unpinned, the widened rail floats over the page rather than pushing it, so
     it needs an edge. Pointing over a nav should not reflow a wide table. */
  box-shadow: var(--shadow-lg);
}

/* Pinned, the page has already made room for it (see layouts/dashboard), so it
   sits in the layout instead of over it and drops the shadow. */
.sidenav--pinned:is(:hover, :focus-within, .sidenav--open) {
  box-shadow: none;
}

/* The app's focus ring is a green glow, which is no ring at all on green. */
.sidenav :focus-visible {
  outline: none;
  box-shadow: var(--rail-focus);
}

/* --- The scrolling list -------------------------------------------------- */
/* Sixteen destinations and five groups is taller than a short window. The list
   takes the slack and scrolls inside itself; the footer below it does not move. */
.sidenav__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--space-3) 0 var(--space-2);
  /* The app's scrollbar is drawn for a light surface — restate it for the rail. */
  scrollbar-color: var(--rail-scrollbar) transparent;
}

.sidenav__scroll::-webkit-scrollbar-thumb {
  background-color: var(--rail-scrollbar);
}

/* Collapsed, a scrollbar would be a stripe down a 64px strip of icons — so hide
   the bar, not the overflow. `overflow-y: hidden` here clips whatever the list
   has already scrolled past: on a short window the rail scrolls to keep the
   current page in view, and the rows above it then vanish with no way to reach
   them until you hover. */
.sidenav:not(:hover):not(:focus-within):not(.sidenav--open) .sidenav__scroll {
  scrollbar-width: none;
}

.sidenav:not(:hover):not(:focus-within):not(.sidenav--open) .sidenav__scroll::-webkit-scrollbar {
  width: 0;
  height: 0;
}

.sidenav__group + .sidenav__group {
  margin-top: var(--space-2);
}

.sidenav__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The gap between rows belongs to the item, not to the row inside it, so that
   the row's own top is the item's top — which is what the active marker below
   measures from. */
.sidenav__list > li {
  position: relative;
}

.sidenav__list > li + li {
  margin-top: 2px;
}

/* --- Group headings ------------------------------------------------------ */
/* Fixed height, whichever of its two forms is showing: the words when there is
   room for them, a short rule when there is not. Nothing below shifts. */
.sidenav__group-heading {
  position: relative;
  display: flex;
  align-items: center;
  height: 28px;
  margin: 0;
  padding: 0 var(--space-5);
}

.sidenav__group-heading-text {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--label-letter-spacing);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--rail-ink-soft);
  /* See the note on .sidenav__link-text: transparent is not hidden. */
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition-fast), visibility var(--transition-fast);
}

.sidenav__group-heading::before {
  content: "";
  position: absolute;
  left: var(--space-5);
  width: 24px;
  height: 1px;
  background: var(--rail-line);
  transition: opacity var(--transition-fast);
}

.sidenav:is(:hover, :focus-within, .sidenav--open) .sidenav__group-heading-text {
  opacity: 1;
  visibility: visible;
  /* The fade is held back until the rail has most of its width, so the words
     arrive in place rather than smearing across the opening. Becoming visible
     is not held back with it — that would fade in from nothing twice. */
  transition: opacity var(--transition-fast) 0.12s, visibility 0s;
}

.sidenav:is(:hover, :focus-within, .sidenav--open) .sidenav__group-heading::before {
  opacity: 0;
}

/* --- Rows ---------------------------------------------------------------- */
.sidenav__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  box-sizing: border-box;
  /* 100% less both gutters — set explicitly so a <button> row (sign out, the
     rail toggle, the theme toggle) fills the same box an <a> row does. */
  width: calc(100% - 2 * var(--sidenav-gutter));
  height: var(--sidenav-row-height);
  margin: 0 var(--sidenav-gutter);
  padding: 0 10px;
  border: none;
  border-radius: var(--radius-md);
  background: none;
  color: var(--rail-ink);
  font-family: var(--font-family-base);
  font-size: var(--font-size-medium);
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.sidenav__link:hover {
  background-color: var(--rail-hover);
  color: var(--rail-ink);
}

.sidenav__link:hover .sidenav__link-icon {
  color: var(--rail-ink);
}

.sidenav__link-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--rail-ink-soft);
  transition: color var(--transition-fast);
}

/* The app's own icons carry their own width and height and vary in proportion,
   so the box is the constant and each icon fits itself inside it. */
.sidenav__link-icon svg {
  width: 100%;
  height: 100%;
}

/* Hidden, not merely transparent. A narrow rail clips the labels but does not
   quite cut them off — the first few pixels of one still fall inside the 64px
   box — and a transparent thing that is still laid out is still a thing: it
   answers to hit testing, to a text selection dragged across it, and to
   anything asking the page what is on screen. The row carries its own
   aria-label (see shared/_sidenav) so hiding the words costs it no name. */
.sidenav__link-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition-fast), visibility var(--transition-fast);
}

.sidenav:is(:hover, :focus-within, .sidenav--open) .sidenav__link-text {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--transition-fast) 0.12s, visibility 0s;
}

/* --- Where you are ------------------------------------------------------- */
/* A brighter row and a full-strength icon, with a marker on the rail's own edge.
   Legible collapsed, where the marker and the icon are all there is to go on. */
.sidenav__link--active,
.sidenav__link--active:hover {
  background-color: var(--rail-active);
  color: var(--rail-ink);
  font-weight: 600;
}

.sidenav__link--active .sidenav__link-icon,
.sidenav__link--active:hover .sidenav__link-icon {
  color: var(--rail-ink);
}

/* The marker hangs off the list item rather than off the row: the row clips its
   own overflow — that is what hides a label while the rail is narrow — so a tab
   sitting outside it, flush on the rail's edge, would be clipped away with it. */
.sidenav__list > li:has(> .sidenav__link--active)::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--sidenav-row-height) / 2);
  width: 3px;
  height: 20px;
  border-radius: var(--radius-full);
  background-color: var(--rail-marker);
  transform: translateY(-50%);
}

/* --- Footer -------------------------------------------------------------- */
.sidenav__footer {
  flex: 0 0 auto;
  padding: var(--space-2) 0 var(--space-3);
  border-top: 1px solid var(--rail-line);
}

.sidenav__footer-form {
  margin: 0;
}

.sidenav__link--rail-toggle,
.sidenav__link--signout {
  margin-top: 2px;
}

/* One icon or the other, never both. Each toggle shows where it will take you:
   the moon while the rail is green, the sun while it is navy; open-panel while
   the rail is only borrowing its width, close-panel once it has been pinned. */
.sidenav__link-icon--pinned,
.sidenav--pinned .sidenav__link-icon--unpinned,
.sidenav__link-icon--dark,
.sidenav--dark .sidenav__link-icon--light {
  display: none;
}

.sidenav--pinned .sidenav__link-icon--pinned,
.sidenav--dark .sidenav__link-icon--dark {
  display: inline-flex;
}

/* ==========================================================================
   Pointerless screens

   Widening on hover is a pointer's idiom. On a touch screen the same gesture
   is a tap that is also trying to follow a link, so the rail stays put and the
   footer's toggle is how it opens. The controller keeps its hover listeners off
   these screens for the same reason.
   ========================================================================== */
@media (hover: none) {
  .sidenav:hover:not(:focus-within):not(.sidenav--open) {
    width: var(--sidenav-width-collapsed);
  }

  .sidenav:hover:not(:focus-within):not(.sidenav--open) .sidenav__link-text,
  .sidenav:hover:not(:focus-within):not(.sidenav--open) .sidenav__group-heading-text {
    opacity: 0;
    visibility: hidden;
  }
}
