/* Universal dictate FAB (ported from Sage Stage) — pinned to the lower-right.
   Dictates into whichever text field was most recently focused. */

.dictate-fab-shell {
  position: fixed;
  /* Anchor INSIDE the right edge of Bootstrap's `.container` at each
     breakpoint, falling back to flush 1.5rem on narrower viewports. */
  right: 1.5rem;
  bottom: 1.5rem;
  /* Above the area-interview overlay (1050) so the FAB stays tappable while
     an interview modal is open — its chat textarea is dictatable too. Below
     the parking-lot sidebar/backdrop (1099/1100), which may cover it. */
  z-index: 1051;
  display: flex;
  /* column-reverse so the button is the BOTTOM-most child of the shell.
     That keeps the button visually anchored at bottom: 1.5rem regardless
     of whether the status pill above it is currently visible. */
  flex-direction: column-reverse;
  align-items: flex-end;
  gap: 0.5rem;
  pointer-events: none; /* children re-enable; status pill never blocks clicks */
  /* Promote to its own compositor layer so the heavy box-shadow + gradient
     don't repaint on every scroll frame. */
  will-change: transform;
  transform: translateZ(0);
  backface-visibility: hidden;
  transition: opacity var(--motion-quick) var(--ease-out), transform var(--motion-quick) var(--ease-out);
}

@media (min-width: 576px)  { .dictate-fab-shell { right: max(1.5rem, calc((100vw - 540px)  / 2 + 1rem)); } }
@media (min-width: 768px)  { .dictate-fab-shell { right: max(1.5rem, calc((100vw - 720px)  / 2 + 1rem)); } }
@media (min-width: 992px)  { .dictate-fab-shell { right: max(1.5rem, calc((100vw - 960px)  / 2 + 1rem)); } }
@media (min-width: 1200px) { .dictate-fab-shell { right: max(1.5rem, calc((100vw - 1140px) / 2 + 1rem)); } }
@media (min-width: 1400px) { .dictate-fab-shell { right: max(1.5rem, calc((100vw - 1320px) / 2 + 1rem)); } }

.dictate-fab {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  height: 56px;
  padding: 0 1.25rem 0 1rem;
  border-radius: 999px;
  border: 1px solid rgba(72, 156, 184, 0.4);
  /* A gradient is a background-IMAGE and leaves background-color transparent,
     so a white label sat on whatever was behind the pill wherever background
     images are dropped (the same bug as the Interview Me button). Real fill
     underneath, gradient as decoration, both ends dark enough for the label. */
  background-color: var(--teal-fill);
  background-image: linear-gradient(135deg, var(--teal-fill), var(--teal-fill-hover));
  color: #fff;
  font-weight: 600;
  font-size: 0.95rem;
  box-shadow:
    0 12px 32px rgba(15, 26, 46, 0.35),
    0 0 0 6px rgba(72, 156, 184, 0.08);
  cursor: pointer;
  transition: transform var(--motion-quick) var(--ease-out), box-shadow var(--motion-quick) var(--ease-out), background var(--motion-quick) var(--ease-out);
}

/* Hover-capable pointers only (spec §6): a tap must not stick this. */
@media (hover: hover) {
  .dictate-fab:hover {
    transform: translateY(-2px);
    box-shadow:
      0 18px 40px rgba(15, 26, 46, 0.45),
      0 0 0 8px rgba(72, 156, 184, 0.14);
  }
}

.dictate-fab:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: 4px;
}

.dictate-fab i {
  font-size: 1.4rem;
  line-height: 1;
}

.dictate-fab.recording {
  background: linear-gradient(135deg, #ff5d5d, #c73838);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.5);
  animation: dictate-fab-pulse 1.4s ease-in-out infinite;
}

.dictate-fab-label {
  letter-spacing: 0.02em;
}

@media (max-width: 540px) {
  .dictate-fab-label {
    display: none; /* collapse to icon-only on small screens */
  }
}

.dictate-fab-status {
  pointer-events: none;
  max-width: 18rem;
  padding: 0.5rem 0.75rem;
  border-radius: 8px;
  background: rgba(15, 26, 46, 0.94);
  color: #fff;
  font-size: 0.8rem;
  line-height: 1.3;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--motion-quick) var(--ease-out), transform var(--motion-quick) var(--ease-out);
}

.dictate-fab-status.visible {
  opacity: 1;
  transform: translateY(0);
}

.dictate-fab-status.troubleshooting {
  max-width: 24rem;
  padding: 0.75rem 0.9rem;
  line-height: 1.35;
  text-align: left;
}

.dictate-fab-status .dictate-troubleshooting-headline {
  font-weight: 600;
  color: var(--gold);
  margin-bottom: 0.2rem;
}

.dictate-fab-status .dictate-troubleshooting-mic {
  font-size: 0.75rem;
  margin-bottom: 0.4rem;
  padding: 0.3rem 0.5rem;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 6px;
  border-left: 2px solid rgba(72, 156, 184, 0.65);
}

.dictate-fab-status .dictate-mic-key {
  color: rgba(255, 255, 255, 0.65);
  margin-right: 0.25rem;
}

.dictate-fab-status .dictate-troubleshooting-sub {
  font-size: 0.75rem;
  opacity: 0.8;
  margin-bottom: 0.35rem;
}

.dictate-fab-status .dictate-troubleshooting-list {
  margin: 0 0 0.5rem;
  padding-left: 1.1rem;
}

.dictate-fab-status .dictate-troubleshooting-list li {
  margin-bottom: 0.25rem;
}

.dictate-fab-status .dictate-troubleshooting-list li:last-child {
  margin-bottom: 0;
}

.dictate-fab-status .dictate-troubleshooting-os {
  font-size: 0.75rem;
  opacity: 0.85;
  padding-top: 0.4rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.dictate-fab-status .dictate-troubleshooting-os strong {
  color: #fff;
  font-weight: 600;
}

/* Glow on whichever field is currently being dictated into. */
.dictate-active-target {
  outline: 2px solid rgba(72, 156, 184, 0.7) !important;
  outline-offset: 2px;
  border-color: rgba(72, 156, 184, 0.6) !important;
  caret-color: var(--teal-accent);
  animation: dictate-active-pulse 1.6s ease-in-out infinite;
  transition: box-shadow var(--motion-quick) var(--ease-out);
}

@keyframes dictate-active-pulse {
  0%, 100% {
    box-shadow:
      0 0 0 4px rgba(72, 156, 184, 0.18),
      0 0 14px 2px rgba(255, 93, 93, 0.30);
  }
  50% {
    box-shadow:
      0 0 0 6px rgba(72, 156, 184, 0.26),
      0 0 22px 4px rgba(255, 93, 93, 0.45);
  }
}

@keyframes dictate-fab-pulse {
  0%, 100% {
    box-shadow:
      0 12px 32px rgba(15, 26, 46, 0.35),
      0 0 0 0 rgba(255, 93, 93, 0.45);
  }
  50% {
    box-shadow:
      0 12px 32px rgba(15, 26, 46, 0.35),
      0 0 0 12px rgba(255, 93, 93, 0);
  }
}

/* Lazy-reveal entry animation. Set on .dictate-fab-shell by the dictate-fab
   controller when a dictatable field is focused for the first time on the
   page. Self-clears after ~1.4s so subsequent re-shows (after listening
   states or DOM mutations) don't replay it. */
.dictate-fab-shell--revealing {
  animation: dictate-fab-enter var(--motion-ceremony) var(--ease-out);
}

/* Subtle one-shot mic pulse that lands AFTER the entry slide settles, so the
   user's eye is drawn to the icon — not to the chrome. */
.dictate-fab-shell--revealing .dictate-fab i {
  animation: dictate-fab-mic-pulse 900ms ease-out 320ms 1 both;
  transform-origin: center center;
}

@keyframes dictate-fab-enter {
  from { opacity: 0; transform: translateY(10px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes dictate-fab-mic-pulse {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.18); }
  100% { transform: scale(1); }
}

/* While the Setting the Stage wizard overlay is up, its own Dictate buttons
   drive this FAB programmatically — the floating button itself just overlaps
   the wizard's footer band. Hide the shell, except mid-recording: the stop
   control and status pill must stay reachable to end a dictation started
   from inside the wizard. */
body:has(.wizard-overlay) .dictate-fab-shell:not(:has(.dictate-fab.recording)) {
  visibility: hidden;
}
