/* Floating chrome: the Ask XPLORE trigger, and scroll-to-top.
 *
 * WHY NOT THE BOTTOM-RIGHT CORNER. That corner is taken, and not by a little:
 * `.bottom-tabs-fixed` (the Table of Contents strip, and the AGS-issues bell)
 * is `position: fixed; bottom: 0; right: 0; width: 380px` — and its HEIGHT
 * grows when the reader expands it. So there is no vertical offset that is safe;
 * anything parked above it is covered the moment the strip opens. A first attempt
 * at a floating Ask XPLORE landed straight on top of both. That is the documented
 * reason the trigger stayed on the project summary page and nowhere else.
 * `#scrollToTop` overlapped the strip too — no longer: it now shifts SIDEWAYS
 * clear of it on the pages that have one (see the scroll-to-top block below),
 * which sidesteps the height problem instead of losing to it.
 *
 * WHERE IT GOES INSTEAD. The right edge, vertically centred. Two reasons, and
 * the first is not aesthetic:
 *
 *   1. It is the only large region of the viewport no fixed chrome claims. The
 *      sidebar owns the left, the navbar the top, `.bottom-tabs-fixed` the
 *      bottom-right 380px. The vertical middle of the right edge is empty on
 *      every page in the platform.
 *   2. The panel is a right-hand slide-over, so a tab on the right edge is
 *      spatially honest: the control sits where the thing it opens comes from,
 *      and the panel slides out from under it.
 *
 * STACKING: below `--assistant-layer-scrim` (10001, assistant-panel.css) so the
 * open slide-over covers the tab rather than the tab floating over the panel —
 * the bug that layering note exists to prevent. Above `.bottom-tabs-fixed`
 * (1005) so it is never buried by page chrome.
 */

.fab-dock {
  position: fixed;
  right: 1.875rem;
  /* BOTTOM-RIGHT, sitting above `.bottom-tabs-fixed` rather than on it.
     `--bottom-tabs-height` is measured from the live strip by the script in
     `_fab_dock.html`, so this clears it whether it is collapsed or expanded,
     and is 0px on the pages that have no strip. The launcher takes the corner
     itself and `.fab-scrolltop` stacks ABOVE it, because the launcher is
     always present while scroll-to-top only appears once you have scrolled —
     the other way round would leave the corner empty and the launcher
     floating. */
  bottom: calc(1.875rem + var(--bottom-tabs-height, 0px));
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .5rem;
  /* The container is taller than its buttons; it must not eat clicks meant for
   * the page underneath. Only the controls themselves are interactive. */
  pointer-events: none;
}

.fab-dock > * {
  pointer-events: auto;
}

/* Renders empty on any page with no project — the launcher gates itself off —
 * and must then reserve nothing. */
.fab-dock:empty {
  display: none;
}

/* ---- Scroll to top ------------------------------------------------------- *
 * Deliberately NOT in the dock. It stays bottom-right, because moving a
 * scroll-to-top button to the middle of the screen to solve someone else's
 * collision would be a worse answer than the collision. Markup moved out of
 * `includes/scrollToTop.html` so it renders once from the chrome instead of
 * per-template.
 *
 * The overlap with `.bottom-tabs-fixed` used to be accepted as a wart, on the
 * grounds that no VERTICAL offset above the strip is safe — true, the strip
 * grows taller when the reader expands it. But that reasoning only rules out
 * moving it UP. Moving it sideways, clear of the strip's 380px, is immune to
 * the strip's height entirely, and is what the rules below do. */

.fab-scrolltop {
  position: fixed;
  right: 1.875rem;
  /* Rides ABOVE `.bottom-tabs-fixed` instead of on top of it.
   *
   * The old note here said no vertical offset above the strip is safe because
   * the strip grows when expanded. That is only true of a STATIC offset:
   * `--bottom-tabs-height` is measured from the live element by the script in
   * `_fab_dock.html` and updated by a ResizeObserver, so the button tracks the
   * strip open or shut. Defaults to 0px, which is the correct answer on the
   * great majority of pages, where no fixed strip exists at all.
   *
   * A horizontal shift was tried first and was worse: it cleared the strip but
   * parked the button on top of the page's own cards. */
  /* One launcher (2.75rem) plus a 0.5rem gap above the dock's own offset. */
  bottom: calc(1.875rem + var(--bottom-tabs-height, 0px) + 3.25rem);
  z-index: 9998;
  border-radius: 50%;
  transition: bottom .18s ease;
}

#scrollToTopButton {
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}

/* `display` is toggled to "block"/"none" by the inline script, so flex centring
 * only applies while it is shown. */
#scrollToTopButton[style*="block"] {
  display: inline-flex !important;
}

/* ---- Ask XPLORE trigger -------------------------------------------------- *
 * A pill rather than a bare icon: "neurology" means nothing on its own, and the
 * feature is new enough that a mystery-meat FAB would simply not be pressed.
 * Collapses to a circle on narrow screens where the label cannot earn its
 * width. */

.assistant-launcher-fab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* A circular mark, not a labelled pill. In the corner the tab shape had
     nothing to attach to, and at this size the wordmark was competing with the
     map's own controls for attention. The accessible name comes from the
     visually-hidden label and `title`. */
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .02em;
  line-height: 1;
  white-space: nowrap;
  color: #fff;
  background-image: linear-gradient(195deg, #42424a 0%, #191919 100%);
  box-shadow: -.25rem .25rem .75rem rgba(0, 0, 0, .2), 0 .5rem 1.5rem rgba(0, 0, 0, .12);
  transition: transform .15s ease, box-shadow .15s ease, opacity .15s ease;
}

.assistant-launcher-fab .material-symbols-rounded {
  font-size: 1.125rem;
  line-height: 1;
}

/* The mark itself. */
.assistant-launcher-mark {
  width: 1.5rem;
  height: 1.5rem;
  object-fit: contain;
  display: block;
}

.assistant-launcher-mark-dark { display: none; }
.dark-version .assistant-launcher-mark-light { display: none; }
.dark-version .assistant-launcher-mark-dark { display: block; }

/* Always visually hidden -- it is the accessible name, so never `display:none`. */
.assistant-launcher-fab-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.assistant-launcher-fab:hover,
.assistant-launcher-fab:focus-visible {
  color: #fff;
  transform: translateY(-2px);
  box-shadow: -.375rem .25rem 1rem rgba(0, 0, 0, .26), 0 .75rem 1.75rem rgba(0, 0, 0, .16);
}

.assistant-launcher-fab:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* HIDDEN while the chat is open, not dimmed.
 *
 * The panel is the thing it opens; leaving the trigger on screen over an open
 * conversation is clutter competing with the panel's own close button. Safe to
 * `display:none`: `close()` removes `.is-open` BEFORE calling `launcher.focus()`,
 * so the button is focusable again by the time focus returns to it. */
.assistant-launcher-fab.is-open {
  display: none;
}

/* ---- While the assistant is docked -------------------------------------- *
 *
 * `body.assistant-docked` (added by assistant-panel.js) means the panel is no
 * longer an overlay: `.main-content` has been pushed left by the width of the
 * dock and the right ~30rem of the viewport belongs to the panel. Fixed chrome
 * anchored to the right edge is therefore now UNDER the panel, and the launcher
 * tab in particular has to stay visible -- it is the handle that closes the
 * thing again.
 *
 * ⚠ **Shift with `right`, never with `transform`.** `.fab-dock` already carries
 * `transform: translateY(-50%)` for its vertical centring; a second `transform`
 * declaration replaces it rather than composing with it, and the tab jumps to
 * the top-right corner. This cost a debugging session the first time.
 *
 * ⚠ The `var()` fallback is not decoration. `--assistant-dock-width` is
 * declared in `assistant-panel.css`, which only loads where the panel renders,
 * while this file loads on EVERY page from `head.html`. Without the fallback the
 * whole declaration would be invalid at computed-value time on any page that
 * ever grew a `.assistant-docked` body without the panel stylesheet.
 *
 * Same 1200px boundary as the panel's own dock rules: below it the panel is
 * still an overlay covering the viewport, and moving the tab out from under it
 * would put it off screen.
 */

@media (min-width: 1200px) {
  body.assistant-docked .fab-dock {
    right: var(--assistant-dock-width, 30rem);
  }

  /* Horizontal only. The vertical `calc()` tracks `--bottom-tabs-height`, which
   * is measured from the live strip by the script in `_fab_dock.html`, and must
   * be left exactly as it is. */
  body.assistant-docked .fab-scrolltop {
    right: calc(1.875rem + var(--assistant-dock-width, 30rem));
  }

  /* Declared on the base selectors so the tab rides back out as well as in --
   * a transition that only exists on the docked rule animates one direction. */
  .fab-dock {
    transition: right .24s ease;
  }

  .fab-scrolltop {
    transition: bottom .18s ease, right .24s ease;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fab-dock,
  .fab-scrolltop {
    transition: none;
  }
}

@media (max-width: 575.98px) {
  .fab-dock {
    right: 1rem;
    bottom: calc(1rem + var(--bottom-tabs-height, 0px));
  }

  .fab-scrolltop {
    right: 1rem;
    /* Keeps both the strip clearance and the launcher clearance -- a bare
       `bottom` here would drop this back on top of one or the other. */
    bottom: calc(1rem + var(--bottom-tabs-height, 0px) + 3.25rem);
  }

  /* Collapses to an edge-hugging half-circle: the label cannot earn its width
   * on a phone, and a tab that covered a third of the screen would be worse
   * than no tab. */
  .assistant-launcher-fab {
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    justify-content: center;
    border-radius: 1.25rem 0 0 1.25rem;
  }

  .assistant-launcher-fab .assistant-launcher-fab-label {
    /* Not `display:none` -- the label is the button's accessible name and a
     * screen reader still needs it. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* ---- Dark ---------------------------------------------------------------- *
 * The dark theme flips the page to near-black, where the dark gradient above
 * disappears into the background. The trigger inverts to a light pill so it
 * stays the most prominent thing in the corner in both themes. */

.dark-version .assistant-launcher-fab {
  color: #191919;
  background-image: linear-gradient(195deg, #f0f2f5 0%, #ced4da 100%);
  box-shadow: 0 .25rem .5rem rgba(0, 0, 0, .45), 0 .5rem 1.5rem rgba(0, 0, 0, .35);
}

.dark-version .assistant-launcher-fab:hover,
.dark-version .assistant-launcher-fab:focus-visible {
  color: #191919;
  box-shadow: 0 .375rem .75rem rgba(0, 0, 0, .5), 0 .75rem 1.75rem rgba(0, 0, 0, .4);
}

.dark-version .assistant-launcher-fab:focus-visible {
  outline-color: #191919;
}
