/*
 * The site strip: one thin bar, the same on every page.
 *
 * ── One file, two deliveries ────────────────────────────────────────────────
 *
 * This is the only copy. The planner bundles it (`main.tsx` imports it, so it
 * works under `npm run dev` as well as in the build), and `docker/Dockerfile`
 * copies this same path to /var/www/spickme/sitenav.css, which the static pages
 * link. It lives here rather than beside those pages because the planner's build
 * context is `web/plan` alone and could not reach it there — whereas the image
 * build sees the whole repository and can reach it here. Two copies would drift,
 * and "identical on every page" is the entire point.
 *
 * ── Why it looks like this ───────────────────────────────────────────────────
 *
 * Navigation here is a *locator*, not a destination. The content is what people
 * came for, so the strip is 40px tall, hairline-bordered, translucent, and set
 * in the muted ink — it recedes until looked at, and lifts on hover or focus.
 * It never repeats the page's own title; the H1 below it does that job better.
 *
 * The path is drawn as a miniature line diagram — an origin node, a hairline,
 * a terminus — because that is the app's own language. Every journey in this
 * product is a thread with stops on it, so the route *through the site* is
 * drawn the same way. It reads as transit signage rather than as website
 * chrome, and it costs no more space than plain text with slashes would.
 *
 * ── Why there is no JavaScript ───────────────────────────────────────────────
 *
 * The legal pages and the connection viewer are served under a CSP whose
 * `script-src` admits nothing beyond the shared /theme.js snippet (and the
 * viewer's own modules) — they deliberately run no page script. A strip that
 * needed script would silently lose its menu exactly there, and would lose it
 * anywhere the moment a script fails to arrive, so the disclosure is a plain
 * <details>. The cost is that the menu
 * closes on its own button rather than on an outside click; the benefit is that
 * it behaves identically under every policy on this origin, and with scripting
 * off entirely.
 *
 * ── Tokens ───────────────────────────────────────────────────────────────────
 *
 * Only the tokens every page defines are used — --paper, --paper-low, --ink,
 * --muted, --outline, --coral — each with a fallback, so a page that has not
 * declared one still renders rather than falling back to unstyled black. Theme
 * switching is left entirely to the host page: this file names no colour of its
 * own, so it follows whatever light/dark mechanism that page already uses.
 */

.sitenav {
  position: sticky;
  top: 0;
  z-index: 60;
  /* Translucent so the content scrolling beneath stays faintly visible: the
     strip reads as a pane over the page rather than a lid on it. */
  background: color-mix(in srgb, var(--paper, #f1efea) 86%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--outline, #c8c3b8) 55%, transparent);
  /* Muted by default; the whole strip lifts to full ink when it is being used. */
  color: var(--muted, #6b6b6b);
  transition: color 160ms ease, background-color 160ms ease;
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .sitenav {
    background: color-mix(in srgb, var(--paper, #f1efea) 72%, transparent);
    -webkit-backdrop-filter: blur(14px) saturate(1.4);
    backdrop-filter: blur(14px) saturate(1.4);
  }
}

.sitenav:hover,
.sitenav:focus-within {
  color: var(--ink, #111418);
  background: color-mix(in srgb, var(--paper, #f1efea) 94%, transparent);
}

/* Aligns the strip's contents with the page body below it: same measure, same
   gutter, so the origin node sits directly over the content's left edge. */
.sitenav-inner {
  /* Each page declares the column it reads in, so the origin node lines up with
     the content's left edge rather than floating away from it. The default is
     the widest page's measure; the planner sets its own. */
  width: min(var(--sitenav-measure, 1180px), 100%);
  margin: 0 auto;
  padding: 0 clamp(18px, 4vw, 48px);
  height: 40px;
  display: flex;
  align-items: center;
  gap: 4px;
}

.sitenav a {
  color: inherit;
  text-decoration: none;
}

/* The planner reads in a much narrower column, and pads it tighter. */
.sitenav--narrow {
  --sitenav-measure: 680px;
}

.sitenav--narrow .sitenav-inner {
  padding: 0 clamp(14px, 4vw, 28px);
}

/* ── Origin: the mark, and the way home ──────────────────────────────────────
 *
 * Deliberately the first thing in the tab order and the leftmost thing on
 * screen. Every page that includes this strip is one click from the front page,
 * which is what the planner in particular was missing — its wordmark reloaded
 * the planner instead of leaving it.
 */
.sitenav-home {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: none;
  padding: 6px 2px;
  border-radius: 8px;
}

.sitenav-home:hover .sitenav-wordmark,
.sitenav-home:focus-visible .sitenav-wordmark {
  color: var(--ink, #111418);
}

/* The origin node of the thread. Solid, coral, and slightly larger than the
   nodes after it — a line has one start. */
.sitenav-dot {
  position: relative;
  width: 9px;
  height: 9px;
  flex: none;
  border-radius: 999px;
  background: var(--coral, #f26a4b);
}

.sitenav-home:hover .sitenav-dot::after,
.sitenav-home:focus-visible .sitenav-dot::after {
  content: '';
  position: absolute;
  inset: -5px;
  border-radius: inherit;
  background: color-mix(in srgb, var(--coral, #f26a4b) 22%, transparent);
}

/* The little count beside the wordmark: how many more quick clicks would open
   what lives behind the logo (see src/lib/knock.mjs). Deliberately small,
   deliberately grey, and the same grey at three as at one — a badge that
   brightened as it filled would be an invitation, and nothing on this strip
   invites anybody to that. Created by script; absent on a page that has never
   been knocked on. */
.sitenav-knock {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: 999px;
  background: color-mix(in srgb, var(--muted, #6b6b6b) 22%, transparent);
  color: var(--muted, #6b6b6b);
  font-size: 0.66rem;
  font-weight: 700;
  line-height: 1;
  opacity: 0;
  transform: scale(0.55);
  transition:
    opacity 0.18s ease,
    transform 0.18s ease;
}

.sitenav-knock[data-on] {
  opacity: 1;
  transform: none;
}

.sitenav-wordmark {
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.01em;
  white-space: nowrap;
  transition: color 160ms ease;
}

/* ── The path ────────────────────────────────────────────────────────────────
 *
 * One <li> per level. Each draws its own connector and node, so the markup
 * stays a plain ordered list and the diagram is entirely presentational.
 */
.sitenav-path {
  display: flex;
  align-items: center;
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.78rem;
  font-weight: 600;
}

.sitenav-path li {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
  /* Room for the connector and the node that precede the label. */
  padding-left: 26px;
  white-space: nowrap;
}

/* The connector: a hairline running back toward the previous stop. */
.sitenav-path li::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 50%;
  width: 12px;
  height: 1px;
  background: color-mix(in srgb, var(--outline, #c8c3b8) 85%, transparent);
}

/* The node: hollow for a stop you can travel back to, solid coral for the one
   you are standing at. */
.sitenav-path li::after {
  content: '';
  position: absolute;
  left: 15px;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -3.5px;
  box-sizing: border-box;
  border: 1.5px solid color-mix(in srgb, var(--outline, #c8c3b8) 95%, transparent);
  border-radius: 999px;
  background: var(--paper, #f1efea);
}

.sitenav-path li[aria-current='page'] {
  color: var(--ink, #111418);
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sitenav-path li[aria-current='page']::after {
  border-color: var(--coral, #f26a4b);
  background: var(--coral, #f26a4b);
}

.sitenav-path a:hover,
.sitenav-path a:focus-visible {
  color: var(--ink, #111418);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.sitenav-spacer {
  flex: 1 1 auto;
  min-width: 8px;
}

/* ── Page-specific controls ──────────────────────────────────────────────────
 *
 * An empty slot the host page fills — the theme switch on the front page, the
 * language and settings buttons in the planner. It sits inside the strip rather
 * than in a second bar of its own, which is what keeps one 40px line the whole
 * chrome budget for a page.
 */
.sitenav-tools {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}

/* ── Quick links ─────────────────────────────────────────────────────────────
 *
 * Shortcuts, not the whole map: the menu beside them holds everything. Hidden
 * on narrow screens, where the same links are one tap away in the menu, so
 * nothing is ever only reachable at one size.
 */
.sitenav-links {
  display: none;
  align-items: center;
  gap: 2px;
  flex: none;
  font-size: 0.78rem;
  font-weight: 600;
}

.sitenav-links a {
  padding: 6px 9px;
  border-radius: 8px;
  white-space: nowrap;
}

.sitenav-links a:hover,
.sitenav-links a:focus-visible {
  color: var(--ink, #111418);
  background: color-mix(in srgb, var(--outline, #c8c3b8) 26%, transparent);
}

/* ── The menu ────────────────────────────────────────────────────────────────*/

.sitenav-more {
  position: relative;
  flex: none;
}

.sitenav-more > summary {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  cursor: pointer;
  list-style: none;
}

/* Safari draws its own triangle unless both of these are said. */
.sitenav-more > summary::-webkit-details-marker {
  display: none;
}

.sitenav-more > summary:hover,
.sitenav-more > summary:focus-visible,
.sitenav-more[open] > summary {
  color: var(--ink, #111418);
  background: color-mix(in srgb, var(--outline, #c8c3b8) 26%, transparent);
}

/* Three rules stacked — a timetable, at 14px. Drawn in CSS rather than fetched
   as an icon, because half of these pages forbid img-src from anywhere but
   this origin and none of them should pay a request for a hamburger. */
.sitenav-burger {
  position: relative;
  display: block;
  width: 14px;
  height: 1.5px;
  border-radius: 2px;
  background: currentColor;
}

.sitenav-burger::before,
.sitenav-burger::after {
  content: '';
  position: absolute;
  left: 0;
  width: 14px;
  height: 1.5px;
  border-radius: 2px;
  background: currentColor;
}

.sitenav-burger::before {
  top: -4.5px;
}

.sitenav-burger::after {
  top: 4.5px;
}

/* Shortened middle rule when open: the same three lines, read as "here". */
.sitenav-more[open] .sitenav-burger {
  width: 9px;
}

.sitenav-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 10;
  min-width: 208px;
  padding: 8px;
  border: 1px solid var(--outline, #c8c3b8);
  border-radius: 12px;
  background: var(--paper-low, var(--paper, #f1efea));
  box-shadow: 0 18px 44px rgb(17 20 24 / 0.16);
  color: var(--ink, #111418);
  font-size: 0.82rem;
  font-weight: 600;
}

.sitenav-panel a {
  display: block;
  padding: 8px 10px;
  border-radius: 8px;
}

.sitenav-panel a:hover,
.sitenav-panel a:focus-visible {
  background: color-mix(in srgb, var(--outline, #c8c3b8) 30%, transparent);
}

/* The page you are already on, listed but not offered. */
.sitenav-panel a[aria-current='page'] {
  color: var(--coral, #f26a4b);
}

.sitenav-panel-label {
  padding: 8px 10px 4px;
  color: var(--muted, #6b6b6b);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.sitenav-panel hr {
  margin: 6px 4px;
  border: 0;
  border-top: 1px solid color-mix(in srgb, var(--outline, #c8c3b8) 60%, transparent);
}

/* Keyboard focus must stay visible against both grounds. */
.sitenav :focus-visible {
  outline: 2px solid var(--coral, #f26a4b);
  outline-offset: 2px;
}

/* ── Sizes ───────────────────────────────────────────────────────────────────
 *
 * The strip never changes shape, only how much of the path it can afford to
 * show. Nothing is reachable at one width and missing at another: what the
 * quick links drop, the menu still carries.
 */

/* Laptop and desktop: the shortcuts appear. */
@media (min-width: 880px) {
  .sitenav-links {
    display: flex;
  }
}

/* Large mobile: the middle of the path folds away, origin and destination stay
   — which is the part that answers "where am I?". */
@media (max-width: 620px) {
  .sitenav-path li:not([aria-current='page']) {
    /* Kept in the accessibility tree; only the label is dropped. */
    padding-left: 26px;
    font-size: 0;
  }

  .sitenav-path li:not([aria-current='page']) a {
    display: none;
  }
}

/* Small mobile: the line tightens, and on a page deep enough to have a path the
   wordmark yields its room to it. On the front page there is no path, so the
   wordmark stays — a lone coral dot is a poor brand and there was space for it
   all along. Browsers without :has() simply keep the wordmark and let the
   current crumb ellipsise, which is the safe way to be wrong. */
@media (max-width: 400px) {
  .sitenav-inner {
    height: 38px;
    gap: 2px;
  }

  .sitenav-inner:has(.sitenav-path) .sitenav-wordmark {
    /* Not display:none — screen readers still announce the link's name. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .sitenav-path {
    font-size: 0.76rem;
  }

  .sitenav-path li {
    padding-left: 22px;
  }

  .sitenav-path li::before {
    left: 2px;
    width: 10px;
  }

  .sitenav-path li::after {
    left: 12px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sitenav,
  .sitenav-wordmark {
    transition: none;
  }
}

/* ── The tools, on the right of the strip ───────────────────────────────────
 *
 * Two controls, in the same place on every page that has them: the language,
 * then the colour theme. They used to be neither. The theme toggle existed
 * once, in the landing page's own <style> and <script>; the planner had a
 * different control that cycled through the three states on one button; the
 * other eight pages had nothing at all, even though every one of them applies
 * a pinned theme. Same markup, same styles, same handler (docker/theme.js)
 * everywhere now.
 *
 * Language is the planner's alone, because it is the only page that has
 * translations. Offering the control where nothing would change is worse than
 * not offering it.
 */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid color-mix(in srgb, var(--outline, #c8c3b8) 70%, transparent);
  border-radius: 999px;
  background: transparent;
}

.theme-toggle button {
  display: grid;
  place-items: center;
  width: 28px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--muted, #6b6b6b);
  cursor: pointer;
  font-size: 0.8rem;
  line-height: 1;
}

.theme-toggle button:hover {
  color: var(--ink, #111418);
}

.theme-toggle button[aria-pressed="true"] {
  background: var(--paper-high, #e2ded4);
  color: var(--ink, #111418);
}

.theme-toggle button:focus-visible {
  outline: 2px solid var(--coral, #f26a4b);
  outline-offset: 1px;
}

/* The language, as its own control rather than three levels down in Settings.
   A <select> was tried and taken out again: at full width it overlapped the
   path beside it. This is the burger's disclosure pattern at a smaller size —
   the current language on the button, the rest in a panel under it. */
.sitenav-lang {
  position: relative;
}

.sitenav-lang > summary {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 26px;
  padding: 0 8px;
  border: 1px solid color-mix(in srgb, var(--outline, #c8c3b8) 70%, transparent);
  border-radius: 999px;
  color: var(--muted, #6b6b6b);
  cursor: pointer;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  list-style: none;
  white-space: nowrap;
}

.sitenav-lang > summary::-webkit-details-marker {
  display: none;
}

.sitenav-lang > summary:hover,
.sitenav-lang[open] > summary {
  color: var(--ink, #111418);
}

.sitenav-lang > summary:focus-visible {
  outline: 2px solid var(--coral, #f26a4b);
  outline-offset: 1px;
}

.sitenav-lang-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 70;
  display: grid;
  min-width: 168px;
  max-height: min(60vh, 420px);
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--outline, #c8c3b8);
  border-radius: 12px;
  background: var(--paper, #f1efea);
  box-shadow: 0 18px 40px rgb(0 0 0 / 0.18);
}

.sitenav-lang-panel button {
  padding: 7px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ink, #111418);
  cursor: pointer;
  font: inherit;
  font-size: 0.82rem;
  text-align: left;
}

.sitenav-lang-panel button:hover {
  background: color-mix(in srgb, var(--outline, #c8c3b8) 30%, transparent);
}

.sitenav-lang-panel button[aria-current="true"] {
  color: var(--coral, #f26a4b);
  font-weight: 700;
}

.sitenav-lang-panel hr {
  height: 1px;
  margin: 5px 4px;
  border: 0;
  background: color-mix(in srgb, var(--outline, #c8c3b8) 60%, transparent);
}

.sitenav-lang-group {
  padding: 6px 10px 2px;
  color: var(--muted, #6b6b6b);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
