/*
 * Copyright (c) 2026 Apurva Nakade. All rights reserved.
 * Released under Apache 2.0 license as described in the file LICENSE.
 * Authors: Apurva Nakade
 */

/* The collapsible sidebar rail's stylesheet -- shipped, with
 * sidebar-rail.js, only when a site sets `mathviz: {sidebar-rail: ...}`.
 * Site chrome for a Quarto website or book with a `style: floating`
 * sidebar, not part of the ojs-* design system, which is why it is not in
 * mathviz.css. Consumes --vm-* tokens only, so it re-themes with them.
 *
 * Loaded as an html dependency, i.e. after Bootstrap's and Quarto's own CSS
 * and before the site's css: files -- the same place in the cascade these
 * rules held when they lived in a site's styles.css. */

/* ── Page grid / collapsible sidebar ─────────────────────────────── */
/* Quarto only makes #quarto-sidebar an off-canvas overlay below 992px
 * (Bootstrap's .collapse.collapse-horizontal); above that it switches to
 * `position: sticky` and reserves its own page-columns grid track. These
 * rules force the off-canvas treatment at every width instead, driven by
 * our own .vm-sidebar-open/.vm-sidebar-pinned classes on <body> (see
 * sidebar-rail.js) rather than Bootstrap's .collapse/.show —
 * bypassing Bootstrap's own JS entirely, so the rail's open/pin/Escape
 * handling is the only thing driving the panel. */

/* Scoped to >=992px on purpose. Below that Quarto's own responsive grid
 * already collapses the sidebar track and sizes the body column to the
 * viewport, and it does it correctly -- an unscoped override here (which
 * this was) forced a `minmax(500px, ...)` floor onto phone viewports too,
 * so a 390px screen laid out a 500px column and scrolled sideways:
 * document.scrollWidth measured 551px against a 390px viewport, clipping
 * the title, byline and every input. The floor is minmax(0, ...) now as
 * well, so the column can always shrink to whatever space actually
 * exists. */
@media (min-width: 992px) {
  body.floating .page-columns {
    grid-template-columns:
      [screen-start] 1.5em [screen-start-inset] 5fr
      [page-start page-start-inset body-start-outset body-start] 1.5em
      [body-content-start] minmax(0, calc(1000px - 3em)) [body-content-end] 1.5em
      [body-end body-end-outset page-end-inset] 1.5em
      [page-end] 5fr [screen-end-inset] 1.5em [screen-end] !important;
  }

  /* ...except on the handful of pages that actually have a table of
   * contents. Quarto places #quarto-margin-sidebar at
   * `grid-column: body-end / page-end`, and the rule above collapses that
   * whole span onto a single 1.5em track -- so the TOC laid out 26px wide
   * against 100px of content on every page that has one (measured at 1440px
   * on privacy, apps/sperners-lemma-geometric-proof and recursive-filters-1d).
   * Restoring Quarto's own right-hand margin tracks just for those pages
   * keeps the wide, centered body column everywhere else, which is the
   * point of the override above: the interactive method pages have no
   * headings at all, so they render no TOC and shouldn't reserve a column
   * for one.
   *
   * :has() rather than Quarto's `fullcontent` body class, which looks like
   * the right discriminator but isn't -- it's set on the homepage listing
   * and NOT on apps/newton-method, which has no TOC either. The
   * presence of the nav element is the only thing that actually tracks
   * whether a TOC exists. (:has() is already used further down this file
   * for the fullscreen chart chain.) */
  body.floating:has(nav#TOC) .page-columns {
    grid-template-columns:
      [screen-start] 1.5em [screen-start-inset] 5fr
      [page-start page-start-inset body-start-outset body-start] 1.5em
      [body-content-start] minmax(0, calc(1000px - 3em)) [body-content-end] 1.5em
      [body-end] minmax(20px, 40px)
      [body-end-outset] minmax(40px, 160px)
      [page-end-inset] minmax(20px, 40px)
      [page-end] 5fr [screen-end-inset] 1.5em [screen-end] !important;
  }
}

/* 66px matches #quarto-header's measured rendered height -- the sidebar's
 * own box starts below the navbar rather than under it (padding-top alone
 * would still paint the sidebar's background/shadow over the navbar's
 * brand text, since both are position: fixed and the sidebar's z-index
 * has to be above the navbar's for the off-canvas panel to show at all). */
#quarto-sidebar.sidebar-navigation {
  position: fixed !important;
  top: 66px !important;
  left: 0 !important;
  bottom: 0 !important;
  width: min(280px, 85vw) !important;
  max-width: min(280px, 85vw) !important;
  height: calc(100vh - 66px) !important;
  z-index: 1055;
  display: flex !important;
  flex-direction: column;
  background: var(--vm-bg);
  border-right: 1px solid var(--vm-border);
  box-shadow: var(--vm-shadow);
  transform: translateX(-100%);
  transition: transform 0.22s ease;
  overflow-y: auto;
}

body.vm-sidebar-open #quarto-sidebar.sidebar-navigation {
  transform: translateX(0);
}

/* Quarto's own backdrop is Bootstrap-collapse-driven and unused here —
 * sidebar-rail.js's own click-outside/Escape handling replaces it. */
#quarto-sidebar-glass {
  display: none !important;
}

/* Below 992px Quarto renders its own .quarto-secondary-nav bar (native
 * hamburger + mobile breadcrumbs) beneath the navbar. #vm-sidebar-rail
 * already replaces the hamburger at every width -- Quarto's own button
 * (and the full-bleed invisible link beside it, both data-bs-toggle=
 * "collapse") still fire Bootstrap's collapse JS on tap, which does
 * nothing here since #quarto-sidebar's visibility is driven by
 * body.vm-sidebar-open, never Bootstrap's .show. Left alone, mobile
 * visitors saw two hamburger-like controls, one of them dead. Keep the
 * breadcrumbs, which live in the same bar. No media query needed --
 * .quarto-secondary-nav is already display:none above 992px. */
.quarto-secondary-nav [data-bs-toggle="collapse"] {
  display: none;
}

/* .quarto-secondary-nav's height varies with breadcrumb depth/length (and
 * can wrap on a narrow phone), so it's measured live by sidebar-rail.js
 * rather than guessed as a constant -- it sets --vm-secondary-nav-height
 * on <html>. Below 992px that bar sits between the navbar and where the
 * sidebar/rail's own top:66px would otherwise place them, so both need to
 * shift down by its height or they overlap it. */
@media (max-width: 991.98px) {
  #quarto-sidebar.sidebar-navigation,
  #vm-sidebar-rail {
    top: calc(66px + var(--vm-secondary-nav-height, 0px)) !important;
  }

  #quarto-sidebar.sidebar-navigation {
    height: calc(100vh - 66px - var(--vm-secondary-nav-height, 0px)) !important;
  }
}

/* The always-visible rail: a slim strip at the left edge with a hamburger
 * toggle, present regardless of sidebar state so there's always something
 * to click to bring the sidebar back. */
/* Only as tall as the buttons it holds. It used to run the full height of
 * the viewport, to catch a pointer drifting into the left edge and preview
 * the sidebar; with that behaviour gone the tall box had no purpose and one
 * real cost, since an element is hit-tested whether or not it paints
 * anything. Below 768px the body column starts at x:26px, inside the rail's
 * 44px width, so that invisible strip sat over the leftmost 21px of the
 * page's own text and swallowed clicks meant for it. */
#vm-sidebar-rail {
  position: fixed;
  top: 66px;
  left: 0;
  width: 2.75rem;
  z-index: 1056;
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: left 0.22s ease;
}

/* The buttons' own surface. Without it the two icons sit in open space with
 * nothing behind them, and the rail reads as an unfinished fragment rather
 * than a control that was cut off. Shaped as a tab hanging off the left
 * edge -- no left border, rounded on the right only -- so it looks attached
 * to the edge it is anchored to, and equally to the sidebar's own edge once
 * the sidebar is open and the rail has moved out to x:280. */
.vm-rail-cluster {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  padding: 0.4rem 0.3rem;
  margin-top: 0.5rem;
  background: var(--vm-surface);
  border: 1px solid var(--vm-border);
  border-left: none;
  border-radius: 0 var(--vm-radius) var(--vm-radius) 0;
  box-shadow: var(--vm-shadow);
}

/* Once open, the sidebar's own box occupies x:0-280px at the same z-index
 * band the rail sits in -- move the rail to the sidebar's right edge
 * instead of leaving it stacked on top of the sidebar's nav tree text. */
body.vm-sidebar-open #vm-sidebar-rail {
  left: min(280px, 85vw);
}

#vm-sidebar-rail button {
  width: 2.1rem;
  height: 2.1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--vm-radius-sm);
  background: transparent;
  color: var(--vm-text-soft);
  cursor: pointer;
}

#vm-sidebar-rail button:hover,
body.vm-sidebar-open #vm-sidebar-rail button[data-vm-toggle] {
  background: var(--vm-surface);
  border-color: var(--vm-border);
  color: var(--vm-text);
}

body.vm-sidebar-pinned #vm-sidebar-rail button[data-vm-pin] {
  color: var(--vm-accent);
  border-color: var(--vm-border);
}

@media (prefers-reduced-motion: reduce) {
  #quarto-sidebar.sidebar-navigation {
    transition: none;
  }
}

/* Narrow screens: the sidebar takes most of the width, and the rail rides
 * its right edge. */
@media (max-width: 768px) {
  #quarto-sidebar.sidebar-navigation { width: min(85vw, 320px) !important; max-width: min(85vw, 320px) !important; }
  body.vm-sidebar-open #vm-sidebar-rail { left: min(85vw, 320px); }
}
