/* The site navigation, in one place.
 *
 * This used to live inline in every page: six copies of the full nav
 * with dropdowns, two copies of a shorter one, and twenty-four pages
 * with no site nav at all. Any change meant editing it everywhere and
 * nothing reported a copy that had drifted.
 *
 * Paired with _includes/site-nav.html. Both are loaded with absolute
 * paths so one copy works at any depth - the site is served from the
 * domain root (CNAME 20belowrpg.com), and the project-pages URL
 * redirects there.
 *
 * Colours come from each page's own :root palette, which every page
 * already defines, so the nav takes on the page it sits in.
 */


  /* ---- skip link ----
   *
   * The nav is about forty links deep once the dropdowns are counted.
   * Without this, reaching a page's actual text by keyboard means forty
   * tab presses, on every page, every time. Hidden off-screen until it
   * takes focus, then it drops into the top-left corner as the first
   * thing on the page.
   */
  .skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: 10px 16px;
    background: var(--accent, #3d84c4);
    color: #fff;
    font: 600 15px/1.2 "Segoe UI", system-ui, sans-serif;
    text-decoration: none;
    border-radius: 0 0 8px 0;
  }

  .skip-link:focus {
    left: 0;
    outline: 3px solid #fff;
    outline-offset: -3px;
  }

  /* ---- top nav ---- */
  .site-nav {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* The bar wraps rather than running off the right edge. There are
       nine top-level items and the widest labels are long, so on a
       narrow-but-not-mobile window they do not fit on one line. */
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    padding: 0.85rem 1.5rem;
    background: rgba(10, 23, 32, 0.92);
    backdrop-filter: blur(6px);
    border-bottom: 1px solid var(--panel-border);
  }
  .site-nav .brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    text-decoration: none;
    color: var(--text);
    font-weight: 700;
    letter-spacing: 0.03em;
    flex-shrink: 0;
  }
  .site-nav .brand img {
    height: 28px;
    width: auto;
    display: block;
  }
  .nav-links {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    /* Tighter between rows than between items, so a wrapped second line
       reads as part of the same bar rather than a separate one. */
    gap: 0.5rem 1.4rem;
    list-style: none;
    margin: 0;
    padding: 0;
    /* flex-basis 0, not auto: with auto the list's full content width is
       its basis, which pushes the whole list onto its own line below the
       brand before it ever wraps internally. At 0 it takes whatever the
       brand leaves and wraps within that, so the brand keeps its place
       on the first line. */
    flex: 1 1 0;
    justify-content: flex-end;
    min-width: 0;
  }
  /* margin: 0 because a page's own list styles reach these items too:
     the case studies set li { margin-bottom: 0.75rem }, which lifted the
     plain links above the dropdown ones and left the bar unlevel. */
  .nav-links > li {
    position: relative;
    margin: 0;
  }
  .nav-links a {
    color: var(--text-dim);
    text-decoration: none;
    font-size: 0.88rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    padding: 0.3rem 0;
    border-bottom: 2px solid transparent;
    transition: color 0.15s ease, border-color 0.15s ease;
    white-space: nowrap;
  }
  .nav-links > li > a:hover {
    color: var(--text);
    border-color: var(--accent);
  }
  /* Store is a link to the email signup until there is a store. */
  .nav-links a.soon { cursor: pointer; text-decoration: none; }
  .nav-links a.soon:hover { opacity: 0.9; }
  .nav-links .soon {
    color: var(--text-dim);
    font-size: 0.88rem;
    font-weight: 600;
    opacity: 0.5;
    cursor: default;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    white-space: nowrap;
  }
  .pill {
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    border: 1px solid var(--panel-border);
    border-radius: 999px;
    padding: 0.1rem 0.45rem;
  }
  .pill.beta {
    border-color: var(--accent);
    color: var(--accent);
  }
  /* .name .pill is gm-references.html's doc-card version pills; it had
     been added to this selector on that page only. Kept here so the
     rule stays in one place. */
  .dropdown a .pill,
  .name .pill {
    margin-left: 0.4rem;
  }
  .nav-toggle {
    display: none;
    background: none;
    border: 1px solid var(--panel-border);
    border-radius: 6px;
    color: var(--text);
    width: 38px;
    height: 34px;
    font-size: 1.1rem;
    cursor: pointer;
    flex-shrink: 0;
  }

  /* dropdown submenus - hover/focus on desktop */
  .has-dropdown > a::after {
    content: " \25BE";
    font-size: 0.7em;
    color: var(--text-dim);
  }
  /* Kept in the layout and hidden with visibility rather than toggled
     with display: none, which cannot be transitioned and so gave the
     menu no grace period at all - a pixel of overshoot closed it. */
  .dropdown {
    display: block;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-4px);
    /* Opens briskly, closes on a delay, so crossing a corner or
       overshooting an item does not dismiss it. */
    transition: opacity 0.12s ease,
                transform 0.12s ease,
                visibility 0s linear 0.12s;
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 230px;
    background: var(--panel);
    border: 1px solid var(--panel-border);
    border-radius: var(--radius);
    padding: 0.4rem;
    margin: 0.5rem 0 0;
    list-style: none;
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.4);
    z-index: 30;
  }
  /* The 0.5rem margin above the panel is dead space the pointer has to
     cross on its way down, and crossing it dropped :hover.
     Bridging it with a pseudo-element on .dropdown does not work: the
     panel is pointer-events:none until it is hovered, and it cannot be
     hovered through a bridge it does not yet accept pointers on.
     Extending the list item's own box downward does work - the pointer
     never leaves .has-dropdown in the first place. Negative margin
     keeps the bar's layout unchanged. */
  .nav-links > .has-dropdown {
    padding-bottom: 0.7rem;
    margin-bottom: -0.7rem;
  }
  /* That padding still left a few pixels of nav showing between the item
     and the panel - measured at 4px, which is plenty to drop the pointer
     and make the menu feel like it is fighting you. The panel carries its
     own transparent lip upward to overlap it, so the two boxes meet with
     no seam.
     This works now where it did not before: the lip belongs to the panel,
     which is only pointer-events:auto while open, and opening is now the
     script's job rather than something the lip has to accomplish. */
  /* A menu near the right edge opens leftward from its item instead of
     running off the window. Hidden menus still take up room, so without
     this the right-most one widened every page and scrolled it sideways.
     site-nav.js sets .align-right by measuring, on load and on resize,
     because the bar wraps and which menu is near the edge changes. */
  .dropdown.align-right {
    left: auto;
    right: 0;
  }
  .dropdown::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: -0.85rem;
    height: 0.85rem;
  }
  /* .open is set by site-nav.js, which holds the menu for a moment after
     the pointer leaves. :hover and :focus-within stay as well, so the
     menu still works with JavaScript off - just without the grace
     period. */
  .has-dropdown.open .dropdown,
  .has-dropdown:hover .dropdown,
  .has-dropdown:focus-within .dropdown {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
    transition: opacity 0.12s ease,
                transform 0.12s ease,
                visibility 0s;
  }
  @media (prefers-reduced-motion: reduce) {
    .dropdown { transition: visibility 0s linear 0.12s; transform: none; }
    .has-dropdown.open .dropdown,
    .has-dropdown:hover .dropdown,
    .has-dropdown:focus-within .dropdown { transition: visibility 0s; }
  }
  .dropdown li {
    padding: 0;
    border: none;
  }
  .dropdown a,
  .dropdown li > .soon {
    display: block;
    padding: 0.45rem 0.6rem;
    font-size: 0.85rem;
    font-weight: 500;
    border-radius: 5px;
    border-bottom: none;
    white-space: normal;
  }
  .dropdown a:hover {
    background: var(--accent-dim);
    color: var(--text);
  }
  .dropdown-heading {
    padding: 0.5rem 0.6rem 0.2rem;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
    border-top: 1px solid var(--panel-border);
    margin-top: 0.3rem;
  }
  .dropdown li.dropdown-heading:first-child {
    border-top: none;
    margin-top: 0;
  }

  @media (max-width: 900px) {
    .nav-links { gap: 1rem; }
  }
  @media (max-width: 780px) {
    .nav-toggle { display: block; }
    .nav-links {
      display: none;
      position: absolute;
      top: 100%;
      left: 0;
      right: 0;
      max-height: calc(100vh - 60px);
      overflow-y: auto;
      flex-direction: column;
      /* The bar wraps on desktop; this panel must not. It is a column
         with a bounded height, so wrapping would spill the tail of the
         menu into a second column off the right edge instead of
         scrolling. */
      flex-wrap: nowrap;
      align-items: flex-start;
      justify-content: flex-start;
      flex: 0 1 auto;
      gap: 0;
      background: var(--panel);
      border-bottom: 1px solid var(--panel-border);
      padding: 0.5rem 1.5rem 1rem;
    }
    .nav-links.open { display: flex; }
    .nav-links > li { width: 100%; padding: 0.6rem 0; border-bottom: 1px solid var(--panel-border); }
    .nav-links > li:last-child { border-bottom: none; }
    .has-dropdown > a::after { display: none; }
    .dropdown {
      display: block;
      /* Always shown here - the mobile panel is an expanded list, not a
         hover menu, so the desktop hidden state has to be undone. */
      opacity: 1;
      visibility: visible;
      pointer-events: auto;
      transform: none;
      transition: none;
      position: static;
      background: none;
      border: none;
      box-shadow: none;
      margin: 0.5rem 0 0;
      padding: 0 0 0 1rem;
    }
    /* No gap to bridge when the list is static, and the negative margin
       would pull the next item up over this one. */
    .nav-links > .has-dropdown { padding-bottom: 0; margin-bottom: 0; }
    .dropdown::before { content: none; }
    .dropdown a { padding: 0.4rem 0; font-size: 0.85rem; color: var(--text-dim); }
  }

/* The license link every 20 Below page carries (_includes/site-footer.html).
   The portfolio pages have their own footers and don't include it. */
.site-footer {
  text-align: center;
  padding: 2.5rem 1rem 2rem;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  color: var(--text-dim, #8fadbe);
}
.site-footer p { margin: 0; }
/* The email signup (app/signup.js) sits above the license line; on the
   home page it has its own slot above that page's footer. */
.site-footer .site-signup { margin: 0 0 1.4rem; }
/* Where to find the team: the community links, one line above the license line. */
.site-footer .site-social { margin: 0 0 0.6rem; }
.home-signup { margin: 2.5rem 0 0; }
.site-footer a { color: var(--text-dim, #8fadbe); }
.site-footer a:hover, .site-footer a:focus-visible { color: var(--accent, #3d84c4); }
