/* ------------------------------
   Mobile navigation
   ------------------------------
   Its own stylesheet, loaded from the shared head partial, for the same
   reason as footer.css: the pages carrying this header are split between
   two page stylesheets — the homepage loads home.css, everything else
   loads site.css — and neither could hold it without the other going
   unstyled.

   Only the small-screen half lives here. The wide-screen bar stays in the
   two page sheets, which style it deliberately differently: a floating
   translucent overlay on the homepage, a plain bordered bar elsewhere.

   Three headers use it: the public one in templates/partials/header.html
   and the signed-in workspace's own topbar in templates/app.html, which
   share the panel, the button and the breakpoint but differ in what they
   hide and in where the open/close wiring lives (the partial's inline
   script; public/js/app.js). Markup and styles move together. */

/* One breakpoint, named once. Below it the row of links is replaced by the
   button; above it the button is gone. 45rem is where "Explore /
   Documentation / Get started" alongside the wordmark stops having
   comfortable air around it rather than where it starts colliding — a nav
   that only just fits already reads as cramped. The same value is in the
   header partial's matchMedia call. */

/* The one link the two copies of the list do not share. "Get started" is
   the only way in that the wide bar offers, and it reaches both forms —
   the register page links across to sign in. The menu keeps the link
   because it has no equivalent second row to fall back on.

   Done here, in one rule, rather than by rendering two different lists:
   the whole point of the "nav-links" partial is that neither copy of that
   list is written by hand, and splitting it to move a single item would
   give the drift it exists to prevent a way back in. */
.site-nav .nav-signin {
  display: none;
}

.nav-toggle {
  display: none;
  place-items: center;
  padding: var(--pf-space-2);
  margin-right: calc(var(--pf-space-2) * -1); /* optical: aligns the icon, not its box, with the page edge */
  border: none;
  background: none;
  color: var(--pf-color-ink);
  cursor: pointer;
}

.nav-toggle svg {
  width: 24px;
  height: 24px;
  /* Stroked, not filled: these are two line drawings, and stroke lets them
     follow currentColor at any size without a second set of paths. */
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
}

/* The panel. A <dialog> in the top layer, so it covers the page whatever
   the header's stacking or containing block happens to be — see the
   partial. Sized to the viewport rather than to its content, because a
   menu of four links should still be the whole screen. */
.nav-menu {
  width: 100dvw;
  max-width: 100dvw;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  padding: var(--pf-space-6);
  border: none;
  background: var(--pf-color-bg);
  color: var(--pf-color-ink);
}

.nav-menu::backdrop {
  background: var(--pf-color-bg);
}

/* showModal() makes the page behind inert but does not stop it scrolling —
   verified: a wheel gesture over the open menu still moved the document
   600px. Nobody can see that happening through an opaque panel, so they
   come back to a page that has silently jumped. */
html:has(.nav-menu[open]) {
  overflow: hidden;
}

/* The panel's own top row, mirroring the header it replaced: wordmark on
   the left, the button that closes it where the button that opened it was. */
.nav-menu__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--pf-space-5);
}

.nav-menu__close {
  display: grid;
  place-items: center;
  padding: var(--pf-space-2);
  margin-right: calc(var(--pf-space-2) * -1);
  border: none;
  background: none;
  color: var(--pf-color-ink);
  cursor: pointer;
}

.nav-menu__close svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
}

/* Big. The whole point of taking the screen is that nothing here needs to
   be economical with it: these are thumb targets, and the type can be the
   size the page's own headings are. */
.nav-menu__links {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--pf-space-5);
  margin-top: var(--pf-space-6);
  font-size: var(--pf-text-2xl);
  font-family: var(--pf-font-display);
  letter-spacing: -0.02em;
}

.nav-menu__links a {
  color: var(--pf-color-ink);
}

/* The call to action keeps its button shape — it is the one link here that
   is not just navigation — but grows to match the type around it. */
.nav-menu__links a.btn {
  margin-top: var(--pf-space-4);
  padding: var(--pf-space-4) var(--pf-space-7);
  font-size: var(--pf-text-lg);
}

/* The signed-in workspace gets the same treatment from the same sheet: its
   topbar carries the same three links plus the MCP token button, and had
   nothing for a narrow screen — at 390px the bar overflowed to 515px and
   pushed the account avatar clean off the right edge, so Settings, Theme
   and Log out were simply unreachable on a phone.

   The panel, the button and the breakpoint are all shared with the public
   header above; only which elements get hidden differs. */
.nav-menu__links .btn {
  /* The MCP button is an action among links, so it keeps its outline but
     drops to the row rhythm rather than the 34px link size. */
  align-self: flex-start;
  font-size: var(--pf-text-base);
}

/* The Admin group in the narrow-screen panel. One child of the link list
   so the gap between Explore and Users is the same as between Projects and
   Explore; inside it, the eyebrow sits close to the link it labels. */
.nav-menu__admin:not([hidden]) {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--pf-space-2);
}

.nav-menu__eyebrow {
  margin: 0;
  font-family: var(--pf-font-body);
  font-size: var(--pf-text-2xs);
  font-weight: var(--pf-weight-regular);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--pf-color-faint);
}

/* Scoped to .site-header / .topbar rather than written as bare class
   selectors, and the reason is load order: this sheet comes before the
   page stylesheet (see the head partial, which puts it there deliberately
   so a page can still override it), and home.css and site.css both declare
   `.site-nav { display: flex }`. Equal specificity would hand the later
   sheet the win and this rule would silently do nothing — as it did on the
   first try. A media query adds no specificity of its own. */
/* ---------------------------------------------------------------------------
   A standing warning about every rule in the block below.
   ---------------------------------------------------------------------------
   This sheet is loaded BEFORE app-chrome.css and the page stylesheets (see
   the head partial, which puts it there deliberately so a page can still
   override it). A media query adds no specificity of its own. So any rule in
   here that restates a selector those sheets also use — .topbar, .brand,
   .topbar-nav, .btn — is a tie, and a tie is decided by source order, which
   this sheet always loses.
   
   Every selector below that looks needlessly specific is that: `header.topbar`
   rather than `.topbar`, `a.brand` rather than `.brand`, `nav.topbar-nav`
   rather than `.topbar-nav`, `.copy-mcp-token.btn` rather than
   `.copy-mcp-token`. Four separate rules have been written the obvious way
   here and silently done nothing. If you add one, out-specify or check it in
   the browser — it will look right in the file either way.
   --------------------------------------------------------------------------- */
@media (max-width: 45rem) {
  /* header.topbar, not .topbar. See the note above: this sheet loads first,
     so an equally specific rule here loses to app-chrome.css's own
     `.topbar { gap: var(--pf-space-4) }` and the media query changes nothing
     about that. Naming the element takes it to (0,1,1) and it applies. */
  header.topbar {
    gap: 0;
  }
  /* Direct children only. The <dialog> is itself inside .topbar, and it
     holds a second Copy MCP token button — a descendant selector hid the
     one in the menu along with the one in the bar. */
  /* The redundant-looking .btn on the last one is load-bearing, and for the
     same reason the scoping above it is: app-chrome.css loads after this
     sheet and gives `.topbar .btn` its inline-flex at (0,2,0), which would
     tie with `.topbar > .copy-mcp-token` and win on order — leaving the
     button on screen next to the very toggle that replaces it. Naming both
     classes takes this to (0,3,0) and settles it. */
  .site-header .site-nav,
  /* Not `.topbar > .navlink`: the links moved inside a <nav> when the brand
     became a sidebar-width column, and a direct-child selector stopped
     matching them — leaving the row of links on screen next to the toggle
     that replaces them. `.topbar nav` does not work either, for the reason
     given above: it ties with app-chrome.css's own rule at (0,1,1) and loses
     on order. Naming the element AND the class takes this to (0,2,1), which
     beats it outright — the same trick as the .btn above, and the reason
     neither of these selectors is as tidy as it looks like it should be. */
  .topbar nav.topbar-nav,
  .topbar > .copy-mcp-token.btn {
    display: none;
  }

  .nav-toggle {
    display: grid;
  }

  /* The toggle belongs at the left, in the space the brand column gives up.
     order rather than moving it in the markup: it is one element serving two
     headers, and the public one wants it on the right. */
  .topbar .nav-toggle {
    order: -1;
    margin-right: 0;
  }

  /* The brand stops being a column. It is 220px, sunken and bordered to line
     up with the sidebar beneath it — and with the sidebar off-canvas there
     is nothing to line up with, so it goes back to being a wordmark. */
  /* a.brand, not .brand: app-chrome.css sets the 220px at (0,2,0) and loads
     after this sheet, so an equally specific rule here would lose on order —
     the same trap the topbar-nav rule above fell into twice. */
  .topbar a.brand {
    width: auto;
    padding-left: var(--pf-space-2);
    border-right: none;
    background: none;
  }

  /* Both sidebars — the workspace's list and a project's token groups — off
     canvas, and back in over the page when the toggle asks for them. Fixed
     rather than a flex child that shrinks to nothing: at this width the
     content needs the whole viewport, and a drawer that pushes it sideways
     would leave the thing you came to read half off-screen.

     top is the bar's own min-height, so the drawer starts under it and the
     toggle that opened it stays reachable. */
  .project-page > .token-sidebar,
  .workspace > .token-sidebar {
    position: fixed;
    top: 52px;
    left: 0;
    bottom: 0;
    z-index: 70;
    width: 260px;
    transform: translateX(-100%);
    transition: transform var(--pf-duration-fast) var(--pf-ease-out);
    box-shadow: var(--pf-shadow-lg);
  }

  :root[data-sidebar="open"] .project-page > .token-sidebar,
  :root[data-sidebar="open"] .workspace > .token-sidebar {
    transform: none;
  }

  /* Dims the page behind the open drawer and catches the click that closes
     it. On the workspace rather than as an extra element, so nothing has to
     be created or torn down. */
  :root[data-sidebar="open"] .project-page::after,
  :root[data-sidebar="open"] .workspace::after {
    content: "";
    position: fixed;
    inset: 52px 0 0;
    z-index: 69;
    background: rgb(0 0 0 / 0.45);
  }

  /* The theme submenu flies out to the left of a 15rem panel, which needs
     25rem of room it does not have on a phone — measured at 390px it ran
     from -24px, off the screen entirely. Below the breakpoint it stacks
     under its parent instead, inside the panel it belongs to. */
  .user-menu .user-menu__panel--sub {
    position: static;
    min-width: 0;
    border: none;
    box-shadow: none;
    background: var(--pf-color-surface-sunken);
  }

  /* Stacked, the submenu's own ground is --pf-color-surface-sunken — the very
     tint app-chrome.css marks the selected theme with, which would leave that
     row indistinguishable from the two above it. Lifted to the raised token
     instead: the same "raised, not inverted" bargain .token-sidebar's active
     row makes, and for the same reason, since what marks the row is being one
     step off its ground and which step that is depends on the ground. The
     green rule and the medium weight carry through unchanged.

     (0,3,0) against app-chrome.css's (0,2,0) — see the note above; at equal
     weight this sheet would lose on order. */
  .user-menu .user-menu__item--choice[aria-checked="true"] {
    background: var(--pf-color-surface);
  }

  /* The chevron points at the side the submenu opens on, so it has to turn
     with it: left becomes down. */
  .user-menu .user-menu__item--parent::after {
    transform: rotate(-45deg);
  }
}

/* A hidden <dialog> is display:none, so the panel needs no counterpart
   rule above the breakpoint — but a window resized wider while it is open
   would leave it there, which is why the partial closes it on the same
   media query. */
