/* ══════════════════════════════════════════════════════
   THE GUIDE — the `?` panel and the spotlight ring
   Loaded after styles.css (whose tokens it uses) and BEFORE print.css, which
   must stay last: print.css overrides the theme colour tokens at equal
   specificity and wins on source order alone. See the header of print.css.
   ══════════════════════════════════════════════════════ */

/* ---- The panel ----
   z-index 90 puts it BELOW .modal-backdrop (100) deliberately. A real modal is
   asking for a decision and should cover the guide; the guide is only
   answering a question about the app. The spotlight, further down, sits above
   everything but the toast — so an answer can still point INTO an open modal
   while the panel itself is hidden behind it. */
.guide-panel {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  width: 360px;
  max-width: 100vw;
  height: 100dvh;
  background-color: var(--bg-sidebar);
  border-left: 1px solid var(--border-color);
  color: var(--text-primary);
  /* No body-scroll lock is set when this opens, so the panel must own its own
     overflow or a long list runs off the bottom with no way to reach it. */
  overflow: hidden;
}

/* In the collapsed step state the panel is a bar at the bottom, not a column:
   it has just pointed at something, and a full-height sheet beside — or on a
   phone, over — the thing it pointed at would defeat the pointing. */
.guide-panel[data-guide-mode="showing"] {
  top: auto;
  bottom: 0;
  left: 0;
  width: auto;
  height: auto;
  border-left: none;
  border-top: 1px solid var(--border-color);
}

.guide-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 16px 12px;
  border-bottom: 1px solid var(--border-color-light);
}

.guide-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
}

.guide-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-md);
  background-color: var(--bg-card);
  color: var(--text-secondary);
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

.guide-close:hover {
  background-color: var(--bg-card-hover);
  color: var(--text-primary);
}

.guide-search-row {
  padding: 12px 16px;
}

.guide-search {
  width: 100%;
  /* 44px is the touch floor the M3 mobile rows settled on. It applies here at
     every width: this is a field somebody stabs at on a phone in a hallway. */
  min-height: 44px;
  padding: 10px 12px;
  font-family: var(--font-family);
  font-size: 14px;
  color: var(--text-primary);
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-md);
}

.guide-search:focus {
  outline: none;
  background-color: var(--bg-input-focus);
  border-color: var(--color-brand);
}

.guide-results {
  flex: 1 1 0;
  /* `flex: 1 1 0`, not `flex: 1`. A bare `flex: 1` is `flex: 1 1 0%` in most
     browsers but keeps an automatic content minimum in some layouts, and a
     scroll container that cannot shrink below its content does not scroll.
     Same trap recorded in the roster section of styles.css. */
  min-height: 0;
  overflow-y: auto;
  padding: 0 16px 16px;
}

.guide-empty {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--text-secondary);
}

/* ---- One question ---- */
.guide-entry {
  border-bottom: 1px solid var(--border-color-light);
}

.guide-question {
  padding: 12px 0;
  /* The touch floor again: a summary row is the primary target in this list. */
  min-height: 44px;
  display: flex;
  align-items: center;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--text-primary);
  cursor: pointer;
  list-style: none;
}

/* Safari still paints the default disclosure triangle without this, which puts
   a marker in the middle of a flex row. */
.guide-question::-webkit-details-marker {
  display: none;
}

.guide-question:hover {
  color: var(--color-brand);
}

.guide-entry[open] .guide-question {
  color: var(--color-brand);
}

.guide-answer {
  padding: 0 0 14px;
}

.guide-answer p {
  margin: 0 0 12px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-secondary);
}

.guide-show-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 8px 12px;
  font-family: var(--font-family);
  font-size: 12px;
  font-weight: 700;
  color: var(--color-brand-fg);
  background-color: var(--color-brand);
  border: 1px solid var(--color-brand);
  border-radius: var(--border-radius-md);
  transition: background-color var(--transition-fast);
}

.guide-show-btn:hover {
  background-color: var(--color-brand-hover);
  border-color: var(--color-brand-hover);
}

/* ---- The collapsed step bar ---- */
.guide-step {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 16px;
  padding: 12px 16px;
}

.guide-step-note {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
}

/* The target went missing — a re-render dropped it, or this backend does not
   show that control. Said in the warning colour rather than silently leaving a
   step bar that describes a ring which is not on screen. */
.guide-step-note[data-guide-missing] {
  color: var(--text-warning);
}

.guide-step-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.guide-step-back,
.guide-step-done {
  min-height: 36px;
  padding: 8px 14px;
  font-family: var(--font-family);
  font-size: 12px;
  font-weight: 700;
  border-radius: var(--border-radius-md);
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.guide-step-back {
  color: var(--text-secondary);
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
}

.guide-step-back:hover {
  color: var(--text-primary);
  background-color: var(--bg-card-hover);
}

.guide-step-done {
  color: var(--color-brand-fg);
  background-color: var(--color-brand);
  border: 1px solid var(--color-brand);
}

.guide-step-done:hover {
  background-color: var(--color-brand-hover);
  border-color: var(--color-brand-hover);
}

/* ---- The spotlight ring ----
   z-index 210 clears the mobile drawer (200) so a nav item can be ringed, and
   stays under the toast (999) so a notification is never hidden behind it.

   pointer-events: none is load-bearing, not a detail. It is what lets somebody
   click the very control being pointed at while it is still being pointed at,
   which is the difference between this and a tour that holds the app hostage.

   There is no scrim, for the same reason. */
.guide-spotlight {
  position: fixed;
  z-index: 210;
  pointer-events: none;
  /* THE STATIC BASE, and it carries the whole job on its own. Everything below
     this rule is animation, and a user who has asked for less motion — or a
     browser mid-repaint — sees exactly this: a solid brand-coloured ring with a
     soft halo. The halo is a box-shadow spread rather than an outline so it
     follows the border radius, and it is what keeps the ring readable against a
     card of almost any colour: one of the two edges always contrasts. */
  border: 2px solid var(--color-brand);
  border-radius: var(--border-radius-md);
  box-shadow: 0 0 0 3px rgba(var(--color-brand-rgb), 0.28);
}

/* THE PULSE — a ring that expands out of the target and fades, continuously,
   the way a phone's settings search shows you the row it just found.
   ::after rather than the element's own box-shadow, because the two jobs are
   different and were fighting: the element keeps its steady halo (above) while
   this pseudo-element does the travelling. Animating the element's own shadow
   meant the resting halo disappeared for most of every cycle, which is what
   made the first version read as a faint flicker rather than a pulse.
   It is inset by the 2px border width and given the same radius, so it starts
   exactly on the ring rather than a few pixels adrift of it. */
.guide-spotlight::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  pointer-events: none;
}

/* ONLY for a device that has not asked for less motion.
   The flat restyle deliberately removed this app's pulse, hover lift and
   checkbox bounce, so re-introducing motion here is a deliberate exception,
   asked for and scoped to one element: the ring can land below the fold of
   somebody's attention even after being scrolled into view, and a moving edge
   is what the eye actually catches.
   It repeats for as long as the ring is up. That is safe HERE, where it would
   not be on permanent chrome, because the ring is transient by construction —
   it exists only between Show me and Done, Back or Escape.
   The global prefers-reduced-motion block in styles.css already clamps
   animation-duration on `*`, so this is belt and braces: the animation is never
   even declared for a user who asked not to have it, rather than declared and
   then neutralised. */
@media not (prefers-reduced-motion: reduce) {
  .guide-spotlight {
    animation: guideRingBreathe 1.8s ease-in-out infinite;
  }

  .guide-spotlight::after {
    animation: guideRingPing 1.8s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
  }
}

/* The travelling ring: starts on the edge at full strength, expands 14px and
   fades to nothing. The alpha reaches 0 before the size does, so it dissolves
   rather than snapping off at the end of the cycle. */
@keyframes guideRingPing {
  0% {
    box-shadow: 0 0 0 0 rgba(var(--color-brand-rgb), 0.6);
  }
  70% {
    box-shadow: 0 0 0 14px rgba(var(--color-brand-rgb), 0);
  }
  100% {
    box-shadow: 0 0 0 14px rgba(var(--color-brand-rgb), 0);
  }
}

/* And the ring itself breathes with it — a small brightening on the same beat,
   so the border and the ping read as one object rather than two effects that
   happen to share an element. */
@keyframes guideRingBreathe {
  0%, 100% {
    box-shadow: 0 0 0 3px rgba(var(--color-brand-rgb), 0.28);
  }
  50% {
    box-shadow: 0 0 0 5px rgba(var(--color-brand-rgb), 0.45);
  }
}

/* ---- Phone ----
   The panel becomes a bottom sheet at the breakpoint the rest of the app uses
   for its drawer. Capped at 70dvh so the top of the app — and the thing the
   guide is about to point at — stays visible behind it. */
@media (max-width: 900px) {
  .guide-panel {
    top: auto;
    bottom: 0;
    left: 0;
    width: auto;
    height: auto;
    max-height: 70dvh;
    border-left: none;
    border-top: 1px solid var(--border-color);
  }

  .guide-step {
    /* Stacked, so a long note is not squeezed into a sliver beside two buttons
       on a 390px screen. */
    flex-direction: column;
    align-items: stretch;
  }

  .guide-step-actions {
    justify-content: flex-end;
  }
}
