/* Connection Status Bar (single-row on desktop, two rows on mobile)
   ────────────────────────────────────────────────────────────────────
   Pinned to the very top of the viewport with position: fixed. The
   bar holds two row groups; on desktop they flow inline as one line,
   on mobile they stack vertically:

     Top row (always grouped together so it stays one line on mobile):
       1. Frequency: Connected/Disconnected/etc. (network health)
       2. Live: mute toggle (left) + LIVE ACTIVITY indicator (right).
          The mute toggle controls client-side playback of the live
          stream; LIVE ACTIVITY reflects /api/heartbeat.radio_activity
          (driven by the Ear service's RMS-based VAD). They share a
          segment with no divider between them.

     Engine row (placed last so it can swallow the full mobile viewport
     width when the status text gets long):
       3. ENGINE: Idle / Processing N transmissions (current_step)

   The bar's total height is exposed as --connection-bar-height so the
   sticky navbar can offset itself to sit flush below it, and the body
   reserves matching padding-top so page content isn't covered. */

:root {
    --connection-bar-height: 32px;
}

.connection-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: var(--connection-bar-height);
    background: #1a1a1a;
    border-bottom: 1px solid #333;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    font-size: 13px;
    color: #888;
    z-index: 1100;
    transition: background 0.3s, color 0.3s;
    line-height: 1;
    padding: 0 12px;
    overflow-x: auto;
    /* Hide scrollbar visually — the bar shouldn't show a horizontal
       scrollbar even if its contents overflow. Users on very narrow
       screens can swipe to see the rest. */
    scrollbar-width: none;
}

.connection-bar::-webkit-scrollbar {
    display: none;
}

/* Each row holds two segments + a divider. On desktop the bar is
   flex-row, so rows + the between-rows divider all flow inline; at
   ≤768px the bar becomes flex-column and rows stack. */
.connection-bar-row {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
    line-height: 1;
}

/* Each segment is a horizontal flex group of icon/label/value. */
.connection-segment {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    line-height: 1;
}

.connection-segment-label {
    color: #aaa;
    font-weight: 700;
    letter-spacing: 0.04em;
    font-size: 11px;
    text-transform: uppercase;
}

/* Vertical pipe separator between segments. Just a thin div, vertically
   centered in the row. */
.connection-divider {
    display: inline-block;
    width: 1px;
    height: 16px;
    background: #333;
    flex-shrink: 0;
}

/* Status indicator dot (used by the Frequency segment) */
.connection-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #22c55e;
    transition: background 0.3s;
    flex-shrink: 0;
}

.connection-bar.connected .connection-dot {
    background: #22c55e;
    box-shadow: 0 0 4px #22c55e;
}

.connection-bar.connected .connection-text {
    color: #d4d4d8;
}

.connection-bar.polling .connection-dot {
    animation: poll-pulse 0.5s ease-in-out;
}

@keyframes poll-pulse {
    0%, 100% {
        transform: scale(1);
        opacity: 1;
    }
    50% {
        transform: scale(1.3);
        opacity: 0.7;
    }
}

.connection-bar.disconnected {
    background: #2d1a1a;
    border-bottom-color: #4a2020;
}

.connection-bar.disconnected .connection-dot {
    background: #dc2626;
    box-shadow: 0 0 4px #dc2626;
    animation: disconnected-pulse 1.5s ease-in-out infinite;
}

.connection-bar.disconnected .connection-text {
    color: #f87171;
}

@keyframes disconnected-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

.connection-bar.reconnecting .connection-dot {
    background: #f59e0b;
    box-shadow: 0 0 4px #f59e0b;
    animation: reconnecting-spin 1s linear infinite;
}

.connection-bar.reconnecting .connection-text {
    color: #fbbf24;
}

@keyframes reconnecting-spin {
    0% { transform: scale(1); }
    50% { transform: scale(0.6); }
    100% { transform: scale(1); }
}

/* ─── Segment 3: Mute Toggle + Live Activity ─────────────────────── */
/* Consolidated segment that merges what used to be separate "Listen
   Live" and "Radio Activity" controls. The mute button on the left
   controls client-side audio playback; the live-activity indicator
   on the right shows whether the Ear service is currently capturing
   audio. No divider between them — they read as a single unit. */

.connection-segment-live {
    gap: 10px;
}

/* Mute / unmute button. Icon-only, no text label, no border. Color
   communicates state: grey when muted, glowing yellow when playing,
   amber+pulse while connecting. drop-shadow (not box-shadow) is used
   for the playing-state glow so the halo follows the SVG silhouette
   instead of forming a rectangle around the button. */
.live-mute-toggle {
    background: transparent;
    border: 0;
    padding: 2px;
    margin: 0;
    color: #888;
    line-height: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.2s, filter 0.3s;
    flex-shrink: 0;
}

.live-mute-toggle:hover {
    color: #d4d4d8;
}

.live-mute-toggle:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
    border-radius: 4px;
}

/* Playing: slow ~2s breathing pulse that varies both color brightness
   and the strength of the surrounding glow. Two stacked drop-shadow
   layers (sharp inner + soft outer) at the peak give a "lit from
   within" feel that a single shadow can't achieve. The 2s period is
   deliberately slower than the 1s loading pulse so the two states
   never get visually confused. */
.live-mute-toggle.playing {
    animation: live-playing-glow 2s ease-in-out infinite;
}

@keyframes live-playing-glow {
    0%, 100% {
        color: #fbbf24;
        filter: drop-shadow(0 0 3px rgba(251, 191, 36, 0.6));
    }
    50% {
        color: #fde047;
        filter:
            drop-shadow(0 0 4px rgba(253, 224, 71, 0.95))
            drop-shadow(0 0 10px rgba(253, 224, 71, 0.7));
    }
}

/* Hover at peak brightness so user feedback is unambiguous even
   mid-pulse (the animation pauses at the brighter color). */
.live-mute-toggle.playing:hover {
    animation-play-state: paused;
    color: #fde047;
    filter:
        drop-shadow(0 0 4px rgba(253, 224, 71, 1))
        drop-shadow(0 0 10px rgba(253, 224, 71, 0.8));
}

.live-mute-toggle.loading {
    color: #f59e0b;
    animation: live-loading-pulse 1s ease-in-out infinite;
}

/* The icon itself spins while the button pulses opacity — same
   period (1s) so the two motions feel like one synchronized
   "connecting" beat rather than competing rhythms. */
.live-mute-toggle.loading .live-mute-icon {
    animation: live-loading-spin 1s linear infinite;
}

@keyframes live-loading-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

@keyframes live-loading-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

.live-mute-icon {
    display: inline-flex;
    line-height: 0;
    transform-origin: center;
}

/* Live Activity indicator. Person-speaking SVG (head always on,
   speech-waves toggled by .active) + "LIVE ACTIVITY" label + 3-bar
   signal meter. Only the bars animate when active; the speech-wave
   layer simply fades in/out so the icon reads as a static "they're
   talking right now" without visually competing with the meter. */
.live-activity {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    line-height: 1;
}

.live-activity-icon {
    display: inline-flex;
    align-items: center;
    color: #555;
    line-height: 0;
    flex-shrink: 0;
    transition: color 0.3s, filter 0.3s;
}

.live-activity-waves {
    opacity: 0;
    transition: opacity 0.3s;
}

.live-activity.active .live-activity-icon {
    color: #22c55e;
    filter: drop-shadow(0 0 4px rgba(34, 197, 94, 0.6));
}

.live-activity.active .live-activity-waves {
    opacity: 1;
}

.live-activity-label {
    color: #aaa;
    font-weight: 700;
    letter-spacing: 0.04em;
    font-size: 11px;
    text-transform: uppercase;
}

.live-activity.active .live-activity-label {
    color: #d4d4d8;
}

.live-activity-signal {
    display: inline-flex;
    align-items: flex-end;
    gap: 2px;
    height: 12px;
}

.signal-bar {
    width: 3px;
    background: #444;
    border-radius: 1px;
    transform-origin: bottom;
    transition: background 0.2s;
}

.live-activity-signal .signal-bar:nth-child(1) { height: 4px; }
.live-activity-signal .signal-bar:nth-child(2) { height: 8px; }
.live-activity-signal .signal-bar:nth-child(3) { height: 12px; }

.live-activity.active .signal-bar {
    animation: signal-active-pulse 0.35s ease-in-out infinite;
    background: #22c55e;
}

.live-activity.active .signal-bar:nth-child(1) { animation-delay: 0s; }
.live-activity.active .signal-bar:nth-child(2) { animation-delay: 0.08s; }
.live-activity.active .signal-bar:nth-child(3) { animation-delay: 0.16s; }

@keyframes signal-active-pulse {
    0%, 100% {
        transform: scaleY(1);
        background: #22c55e;
        box-shadow: 0 0 4px rgba(34, 197, 94, 0.5);
    }
    50% {
        transform: scaleY(1.6);
        background: #4ade80;
        box-shadow: 0 0 8px rgba(74, 222, 128, 0.8);
    }
}

/* ─── Segment 2: Backend Status (ENGINE) ─────────────────────────── */
/* Used inside the engine segment of the connection bar. Compact label
   + value pair. .active state lights the dot and brightens the text. */

.backend-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: #888;
    line-height: 1;
}

.backend-status-icon {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #555;
    display: inline-block;
    flex-shrink: 0;
    transition: background 0.3s, box-shadow 0.3s;
}

.backend-status.active .backend-status-icon {
    background: #22c55e;
    box-shadow: 0 0 4px #22c55e;
    animation: backend-active-pulse 1s ease-in-out infinite;
}

@keyframes backend-active-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.55; }
}

.backend-status-label {
    color: #aaa;
    font-weight: 700;
    letter-spacing: 0.04em;
    font-size: 11px;
    text-transform: uppercase;
}

.backend-status-text {
    color: #888;
}

.backend-status.active .backend-status-text {
    color: #4ade80;
}

/* Push the document down by the bar's height so the fixed bar doesn't
   cover the top of the page (the navbar's top: var(--connection-bar-height)
   handles the navbar's own offset). */
body {
    padding-top: var(--connection-bar-height);
}

/* ─── Responsive layout ──────────────────────────────────────────
   At ≤768px we DON'T shrink fonts/icons. Instead, the bar flips to
   a three-row stack at the same desktop content size:
     Row 1 (top)    — Frequency + Mute + LIVE ACTIVITY (single line)
     Row 2 (engine) — ENGINE: <state>
   The between-row divider is hidden in the stacked layout (the row
   break itself separates them). When the engine is active (i.e.
   anything other than Idle), the engine row left-justifies and uses
   the full row width so the longer status text (e.g. "Processing 1
   transmission (Transcribing)") fits cleanly across mobile widths. */

@media (max-width: 768px) {
    :root {
        /* Two rows of full-size content. ~28px per row plus inter-row
           gap and padding. */
        --connection-bar-height: 64px;
    }

    .connection-bar {
        flex-direction: column;
        justify-content: center;
        gap: 4px;
        /* Zero horizontal padding on the bar itself; rows handle their
           own padding so the engine row can left-justify all the way
           to the viewport edge when active. */
        padding: 4px 0;
        overflow-x: hidden;
    }

    /* Each row is a self-contained flex group of segments + internal
       dividers; rows stack vertically inside the bar. */
    .connection-bar-row {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        padding: 0 12px;
    }

    /* Hide the dividers that separate the row groups on desktop.
       In the stacked layout the row break itself is the separator. */
    .connection-divider-between-rows {
        display: none;
    }

    /* When the engine is active (BackendStatus has the .active class —
       i.e. processing or clustering), left-justify the engine row and
       use the full row width. The :has() selector lets the row react to its
       descendant's state without prop drilling. overflow-x: auto allows
       a horizontal swipe if the status text is long enough to overflow. */
    .connection-bar-row-engine:has(.backend-status.active) {
        justify-content: flex-start;
        padding: 0 8px 0 8px;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .connection-bar-row-engine:has(.backend-status.active)::-webkit-scrollbar {
        display: none;
    }

    /* Keep the engine status's segments on a single line so they don't
       wrap mid-text inside the row; horizontal scroll catches overflow. */
    .connection-bar-row-engine .backend-status,
    .connection-bar-row-engine .backend-status-text {
        white-space: nowrap;
    }
}

@media (max-width: 480px) {
    /* On the smallest phones, the top row (Frequency + Mute + LIVE
       ACTIVITY) packs three segments onto a single line and may
       overflow. Allow swipe-scroll so users can reach the right edge
       even when the row exceeds the viewport. */
    .connection-bar-row-top {
        overflow-x: auto;
        scrollbar-width: none;
    }

    .connection-bar-row-top::-webkit-scrollbar {
        display: none;
    }

    .connection-bar-row {
        padding: 0 8px;
    }
}
