/* np-mic.css — the shared recording UI: the mic button's active state, the floating
   indicator, and the leave-while-recording dialog.

   Loaded by BOTH _Layout and _LayoutAnon, because a patient dictating into an external
   form needs exactly the same signal a clinician does. It is self-contained (no
   dependency on np-theme.css tokens beyond graceful var() fallbacks) so it renders
   identically on the anonymous pages, which load a much smaller stylesheet set. */

/* ── Recording state on the mic control itself ────────────────────────────────
   Every mic in the app takes the class `recording` while listening (applied by
   NeuraplexVoice.dictate). These selectors cover all four rails so the pulse is the
   same wherever the button lives:
     .np-ta__btn--mic  internal shared textarea tools
     .icon-btn.mic     the public wizard rail (pre-assessment, registration)
     .np-mic-btn       anything new                                            */
.np-ta__btn--mic.recording,
.icon-btn.mic.recording,
.np-mic-btn.recording {
    /* Brand primary, not the previous alert red. Red is this product's "not started /
       hazard" colour (§6.6) and spending it on a microphone that is working normally
       made a routine state read as a problem. The recording signal is carried by the
       filled treatment, the pulse, the floating indicator and the button's own
       aria-label — never by hue alone. */
    color: #FFFFFF;
    background: var(--np-color-brand-primary, #741F7B);
    border-color: var(--np-color-brand-primary, #741F7B);
    /* Two rings, offset, so the pulse reads as a live signal rather than a slow
       fade — at 1.4s a single ring looks like a hover transition. */
    animation: np-mic-pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
    position: relative;
}

/* A second, slower halo behind the button. Purely decorative, so it is a
   pseudo-element and never affects layout. */
.np-ta__btn--mic.recording::after,
.icon-btn.mic.recording::after,
.np-mic-btn.recording::after {
    content: "";
    position: absolute;
    inset: -2px;
    border-radius: inherit;
    border: 2.5px solid rgba(var(--np-color-brand-primary-rgb, 116, 31, 123), 0.75);
    animation: np-mic-halo 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
    pointer-events: none;
}

/* The rails style their own hover/focus; while recording the filled brand state has
   to win, or hovering the button to stop it makes it look like it already stopped. */
.np-ta__btn--mic.recording:hover,
.np-ta__btn--mic.recording:focus,
.icon-btn.mic.recording:hover,
.icon-btn.mic.recording:focus,
.np-mic-btn.recording:hover,
.np-mic-btn.recording:focus {
    color: #FFFFFF;
    background: var(--np-color-brand-primary-hover, #581762);
    border-color: var(--np-color-brand-primary-hover, #581762);
}

@keyframes np-mic-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(var(--np-color-brand-primary-rgb, 116, 31, 123), 0.6); }
    50%      { box-shadow: 0 0 0 8px rgba(var(--np-color-brand-primary-rgb, 116, 31, 123), 0); }
}

@keyframes np-mic-halo {
    0%   { opacity: 0.9; transform: scale(1); }
    70%  { opacity: 0;   transform: scale(1.35); }
    100% { opacity: 0;   transform: scale(1.35); }
}

/* The SDK is loading (first use downloads ~1MB) — spin, don't pulse. */
.np-mic--working svg { animation: np-mic-spin 0.8s linear infinite; }
@keyframes np-mic-spin { to { transform: rotate(360deg); } }

/* Dictation not available (no Azure Speech configuration for this tenant, or the
   browser cannot reach a microphone) — hide every mic control rather than offer a
   button that can only fail. np-mic.js stamps the class on <html>, so this covers
   the wizard rails that are re-generated on every step as well as static markup. */
.np-mic-unavailable [data-mic],
.np-mic-unavailable [data-ext-mic],
.np-mic-unavailable [data-np-ta-mic] { display: none !important; }

/* The public wizard rails pair each button with a "Speak" caption in a .tool-stack.
   Hiding only the button would leave the caption behind, labelling nothing. :has() is
   the whole-group rule; the button rule above stays as the fallback for engines
   without it, where a stray caption is a cosmetic flaw rather than a broken control. */
.np-mic-unavailable .tool-stack:has([data-mic]) { display: none !important; }

/* ── The floating indicator ───────────────────────────────────────────────────
   Fixed to the viewport, bottom-right by default, draggable anywhere. Visible for
   exactly as long as the microphone is live. */
.np-mic-indicator {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 1080;               /* above sticky headers and rails, below <dialog> */
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    max-width: min(20rem, calc(100vw - 32px));
    border-radius: 999px;
    /* Brand primary, not the slate-black it shipped with. The indicator is a piece of
       product chrome floating over the page, and a near-black pill belonged to no part
       of the app's visual language — on an organisation's own branded form it read as
       something the browser had put there. The fallbacks keep it correct on the
       anonymous layouts if the theme tokens ever fail to load. */
    background: var(--np-color-brand-primary, #741F7B);
    color: #FFFFFF;
    box-shadow: 0 8px 24px rgba(var(--np-color-brand-primary-rgb, 116, 31, 123), 0.35);
    font-size: 0.8125rem;
    line-height: 1.25;
    cursor: grab;
    touch-action: none;          /* the element handles its own pointer gestures */
    user-select: none;
}

.np-mic-indicator[hidden] { display: none; }
.np-mic-indicator--dragging { cursor: grabbing; box-shadow: 0 12px 32px rgba(var(--np-color-brand-primary-rgb, 116, 31, 123), 0.5); }
.np-mic-indicator:focus-visible { outline: 3px solid #FFFFFF; outline-offset: 2px; }

/* The live dot — the mic glyph on a light disc, pulsing in step with the button so
   the two read as one state. Light-on-brand now that the pill itself is the brand
   colour: a filled circle in the same hue would disappear into its own background. */
.np-mic-indicator__pulse {
    position: relative;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: #FFFFFF;
    color: var(--np-color-brand-primary, #741F7B);
}

.np-mic-indicator__pulse svg { width: 16px; height: 16px; }

.np-mic-indicator__pulse::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2.5px solid rgba(255, 255, 255, 0.85);
    animation: np-mic-halo 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

.np-mic-indicator__text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.np-mic-indicator__title { font-weight: 400; letter-spacing: 0.01em; }

/* The field name can be long; one line with an ellipsis keeps the pill a pill. */
.np-mic-indicator__target {
    opacity: 0.75;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.np-mic-indicator__go,
.np-mic-indicator__stop {
    flex: 0 0 auto;
    border: 1px solid rgba(255, 255, 255, 0.35);
    background: transparent;
    color: inherit;
    border-radius: 999px;
    padding: 4px 10px;
    font: inherit;
    font-size: 0.75rem;
    cursor: pointer;
}

.np-mic-indicator__go:hover,
.np-mic-indicator__stop:hover { background: rgba(255, 255, 255, 0.14); }
.np-mic-indicator__go:focus-visible,
.np-mic-indicator__stop:focus-visible { outline: 3px solid #FFFFFF; outline-offset: 2px; }
.np-mic-indicator__stop { border-color: rgba(255, 255, 255, 0.65); font-weight: 400; }

.np-mic-indicator__grip { opacity: 0.45; letter-spacing: -2px; font-size: 0.75rem; }

/* Phones: the pill spans the width so the buttons stay comfortably tappable. */
@media (max-width: 480px) {
    .np-mic-indicator {
        left: 8px;
        right: 8px;
        max-width: none;
        border-radius: 12px;
    }
    .np-mic-indicator__grip { display: none; }
}

/* The field being dictated into, briefly highlighted after "Go to field" so the eye
   lands on it rather than on whatever else is mid-viewport. */
.np-mic-target-flash {
    animation: np-mic-flash 1.2s ease-out 1;
}

@keyframes np-mic-flash {
    0%   { box-shadow: 0 0 0 0 rgba(var(--np-color-brand-primary-rgb, 116, 31, 123), 0.6); }
    100% { box-shadow: 0 0 0 12px rgba(var(--np-color-brand-primary-rgb, 116, 31, 123), 0); }
}

/* ── Leave-while-recording dialog ─────────────────────────────────────────── */
.np-mic-dialog {
    border: none;
    border-radius: 12px;
    padding: 0;
    max-width: 26rem;
    width: calc(100vw - 32px);
    box-shadow: 0 16px 48px rgba(16, 24, 40, 0.28);
    color: #1D2939;
    background: #FFFFFF;
}

.np-mic-dialog::backdrop { background: rgba(16, 24, 40, 0.45); }
.np-mic-dialog__body { padding: 20px; }
.np-mic-dialog__title { margin: 0 0 8px; font-size: 1.0625rem; font-weight: 400; }
.np-mic-dialog__text { margin: 0 0 8px; }
.np-mic-dialog__hint { margin: 0 0 16px; font-size: 0.8125rem; opacity: 0.72; }

.np-mic-dialog__actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    flex-wrap: wrap;
}

/* The anonymous layouts do not load the np-btn component styles, so the dialog's
   buttons get a self-contained baseline here. On authenticated pages np-theme.css
   loads later and wins, so the buttons match the rest of the app. */
.np-mic-dialog .np-btn {
    border-radius: 8px;
    padding: 8px 14px;
    font: inherit;
    cursor: pointer;
    border: 1px solid #D0D5DD;
    background: #FFFFFF;
    color: #1D2939;
}

/* "Stop Recording" is the SAFE choice here (the alternative is leaving with the
   microphone live), so it takes the brand primary like any other confirm — the alert
   red it carried on the anonymous layouts made the safe option look like the
   dangerous one. On authenticated pages np-theme.css already supplied the brand fill;
   this is the anonymous-layout fallback catching up with it. */
.np-mic-dialog .np-btn--primary {
    background: var(--np-color-brand-primary, #741F7B);
    border-color: var(--np-color-brand-primary, #741F7B);
    color: #FFFFFF;
}

@media (forced-colors: active) {
    .np-mic-indicator { border: 1px solid CanvasText; }
    .np-mic-indicator__go,
    .np-mic-indicator__stop { border: 1px solid CanvasText; }
}

/* Motion sensitivity: the pulse is decorative reinforcement. The indicator's
   presence, its text and the button's colour all still say "recording", so removing
   the animation costs no information. */
@media (prefers-reduced-motion: reduce) {
    .np-ta__btn--mic.recording,
    .icon-btn.mic.recording,
    .np-mic-btn.recording,
    .np-ta__btn--mic.recording::after,
    .icon-btn.mic.recording::after,
    .np-mic-btn.recording::after,
    .np-mic-indicator__pulse::after,
    .np-mic-target-flash,
    .np-mic--working svg {
        animation: none;
    }
}
