#nexus-v4-presence #nxv4-rail {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  max-height: min(760px, calc(100dvh - 96px));
  overflow: hidden;
}

#nexus-v4-presence #nxv4-rail .nxv4-body,
#nexus-v4-presence #nxv4-rail [data-nxv4-panel-body] {
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-bottom: 16px;
}

#nexus-v4-presence #nxv4-rail .nxv4-footer,
#nexus-v4-presence #nxv4-rail [data-nxv4-panel-footer] {
  position: relative;
  z-index: 2;
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(18px);
  border-top: 1px solid rgba(15, 23, 42, 0.08);
}

#nexus-v4-presence .nxv4-insight-card,
#nexus-v4-presence .nxv4-cues-section,
#nexus-v4-presence .nxv4-actions-section,
#nexus-v4-presence .nxv4-form-assist-card,
#nexus-v4-presence .nxv4-compact-voice-summary,
#nexus-v4-presence .nxv4-transcript-panel {
  overflow: visible;
}

#nexus-v4-presence .nxv4-voice-status-card,
#nexus-v4-presence .nxv4-legacy-voice-controls {
  display: none !important;
}

#nexus-v4-presence .nxv4-cues.nxv4-cue-grid .nxv4-cue {
  min-height: 56px;
}

#nexus-v4-presence .nxv4-cues.nxv4-cue-grid .nxv4-cue h4,
#nexus-v4-presence .nxv4-cues.nxv4-cue-grid .nxv4-cue p {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Callout geometry/sizing/z-index (bottom, max-width, z-index) now lives entirely in
   nexus-ai-v4-adaptive-presentation.css. This rule used to duplicate those three properties
   with a plain ID selector, which - being more specific than that file's
   "#nexus-v4-presence .nxv4-micro-speakout" class rule - silently won every time regardless of
   viewport or the newer file's media queries: the callout was actually sitting at z-index:40
   (behind most of the panel) and bottom:92px, not the values the other file's comments claimed.
   Removed rather than left as a second, competing source of truth. */

#nexus-v4-presence.nxv4-mode-compact #nxv4-cues .nxv4-cue:nth-child(n+3) {
  display: none;
}

#nexus-v4-presence .nxv4-disabled-secondary {
  display: none !important;
}

#nexus-v4-presence .nxv4-reasoning-chip {
  display: inline-flex;
  align-items: center;
  margin: 4px 0 8px;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1px solid rgba(15, 23, 42, 0.14);
  background: #f8fafc;
  color: #334155;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .01em;
}

#nexus-v4-presence .nxv4-reasoning-wrap {
  margin-top: 8px;
}

#nexus-v4-presence .nxv4-reasoning-details {
  margin-top: 6px;
  border: 1px solid rgba(148, 163, 184, 0.35);
  border-radius: 10px;
  background: #f8fafc;
  color: #334155;
  font-size: 12px;
  line-height: 1.45;
  white-space: pre-wrap;
  padding: 8px 10px;
}

#nexus-v4-presence.nxv4-closed-world .nxv4-cues-section {
  display: none !important;
}

/*
Orb state -> visual language. Each data-nexus-voice-state selector sets the --nexus-orb-*
variables (single source of truth for that state's color/intensity/pulse speed) which the
consolidated #nxv4-orb rule below actually applies as box-shadow - avoids re-deriving the same
three-layer box-shadow syntax per state and keeps colors consistent with the values the emotion
engine (data-nexus-emotion, nexus-ai-v4-living-motion.css) and the 3D renderer's own accent
colors already use.
*/
#nexus-v4-presence[data-nexus-voice-state="off"] #nxv4-orb,
#nexus-v4-presence[data-nexus-voice-state="conversation-ready"] #nxv4-orb,
#nexus-v4-presence[data-nexus-voice-state="paused"] #nxv4-orb {
  --nexus-orb-ring: rgba(34, 197, 94, 0.16);
  --nexus-orb-glow: transparent;
  --nexus-orb-pulse-speed: 4200ms;
}

#nexus-v4-presence[data-nexus-voice-state="starting"] #nxv4-orb {
  --nexus-orb-ring: rgba(226, 232, 240, 0.22);
  --nexus-orb-glow: rgba(248, 250, 252, 0.28);
  --nexus-orb-pulse-speed: 1500ms;
  animation: nxv4OrbStartingPulse var(--nexus-orb-pulse-speed) ease-in-out infinite;
}

#nexus-v4-presence[data-nexus-voice-state="listening"] #nxv4-orb {
  --nexus-orb-ring: rgba(34, 197, 94, 0.18);
  --nexus-orb-glow: rgba(34, 197, 94, 0.45);
  --nexus-orb-pulse-speed: 2200ms;
  filter: saturate(1.12);
}

#nexus-v4-presence[data-nexus-voice-state="listening"] #nxv4-orb .nxv5-orb-host {
  filter: hue-rotate(65deg) saturate(1.35) brightness(1.05);
}

#nexus-v4-presence[data-nexus-voice-state="thinking"] #nxv4-orb .nxv5-orb-host {
  filter: saturate(1.1) brightness(1.02);
}

#nexus-v4-presence[data-nexus-voice-state="recovering"] #nxv4-orb .nxv5-orb-host {
  filter: hue-rotate(14deg) saturate(1.15) brightness(1.02);
}

#nexus-v4-presence[data-nexus-voice-state="thinking"] #nxv4-orb {
  --nexus-orb-ring: rgba(37, 99, 235, 0.2);
  --nexus-orb-glow: rgba(59, 130, 246, 0.38);
  --nexus-orb-pulse-speed: 2600ms;
}

/* Gentle readying state between Thinking and Speaking - covers TTS synthesis/fetch latency.
   Deliberately calmer than the eventual Speaking pulse (lower glow opacity, no animation) so it
   reads as "about to speak" rather than "speaking now". */
#nexus-v4-presence[data-nexus-voice-state="preparing-speech"] #nxv4-orb {
  --nexus-orb-ring: rgba(230, 57, 70, 0.14);
  --nexus-orb-glow: rgba(230, 57, 70, 0.20);
  --nexus-orb-pulse-speed: 2000ms;
}

#nexus-v4-presence[data-nexus-voice-state="speaking"] #nxv4-orb {
  --nexus-orb-ring: rgba(230, 57, 70, 0.22);
  --nexus-orb-glow: rgba(230, 57, 70, 0.40);
  --nexus-orb-pulse-speed: 1300ms;
  animation: nxv4OrbSpeakingGlowPulse var(--nexus-orb-pulse-speed) ease-in-out infinite;
}

/* Restarting/waiting shares the same restrained amber "reconnecting" treatment as recovering -
   both are transient, non-critical states (see setConversationState's Restarting -> "recovering"
   mapping in nexus-voice-client.js). Error is a real failure and gets its own red, distinct from
   the amber used for "still working on it" - previously both shared the same amber box-shadow,
   which meant a genuine error looked identical to a normal reconnect. */
#nexus-v4-presence[data-nexus-voice-state="recovering"] #nxv4-orb {
  --nexus-orb-ring: rgba(245, 158, 11, 0.18);
  --nexus-orb-glow: rgba(251, 191, 36, 0.34);
  --nexus-orb-pulse-speed: 2400ms;
}

#nexus-v4-presence[data-nexus-voice-state="error"] #nxv4-orb {
  --nexus-orb-ring: rgba(230, 57, 70, 0.24);
  --nexus-orb-glow: rgba(230, 57, 70, 0.42);
  --nexus-orb-pulse-speed: 2400ms;
}

#nxv4-orb {
  box-shadow:
    0 0 0 4px var(--nexus-orb-ring, transparent),
    0 0 22px var(--nexus-orb-glow, transparent),
    0 18px 46px rgba(15, 23, 42, 0.22);
  transition: box-shadow 0.4s ease, filter 0.4s ease;
}

@keyframes nxv4OrbStartingPulse {
  0%, 100% { box-shadow: 0 0 0 3px var(--nexus-orb-ring, transparent), 0 0 14px var(--nexus-orb-glow, transparent), 0 18px 46px rgba(15, 23, 42, 0.22); }
  50% { box-shadow: 0 0 0 5px var(--nexus-orb-ring, transparent), 0 0 22px var(--nexus-orb-glow, transparent), 0 18px 46px rgba(15, 23, 42, 0.22); }
}

@keyframes nxv4OrbSpeakingGlowPulse {
  0%, 100% { box-shadow: 0 0 0 4px var(--nexus-orb-ring, transparent), 0 0 18px var(--nexus-orb-glow, transparent), 0 18px 46px rgba(15, 23, 42, 0.22); }
  50% { box-shadow: 0 0 0 5px var(--nexus-orb-ring, transparent), 0 0 26px var(--nexus-orb-glow, transparent), 0 18px 46px rgba(15, 23, 42, 0.22); }
}

@media (prefers-reduced-motion: reduce) {
  #nexus-v4-presence[data-nexus-voice-state="starting"] #nxv4-orb,
  #nexus-v4-presence[data-nexus-voice-state="speaking"] #nxv4-orb {
    animation: none;
  }
}

#nexus-v4-presence.nxv4-conversation-focus [data-nxv4-cues],
#nexus-v4-presence.nxv4-conversation-focus [data-nxv4-form-assist],
#nexus-v4-presence.nxv4-conversation-focus [data-nxv4-briefing-watch] {
  display: none !important;
}

#nexus-v4-presence.nxv4-conversation-focus [data-nxv4-transcript-panel] {
  display: flex;
  flex-direction: column;
  min-height: 280px;
  max-height: min(52vh, 520px);
}

#nexus-v4-presence.nxv4-conversation-focus [data-nxv4-transcript-log] {
  overflow-y: auto;
  scroll-behavior: smooth;
}

@media (max-width: 768px) {
  #nexus-v4-presence #nxv4-rail {
    max-height: calc(100dvh - env(safe-area-inset-top) - 16px);
  }
}
