/* Voice Chat - Full Screen Session */

/* This immersive overlay covers the whole viewport, and it FLIPS WITH THE APP
   THEME: a warm "paper" world in light mode, an evergreen "room at dusk" world
   in dark mode. The brand accents are identical in both — gold = you/the
   counselor, sage = the simulated client, clay = the system thinking, red =
   stop/record. Only the ground, text, and translucent panels flip.

   The flip runs through the --vc-* tokens below, built on the --rvs-* brand
   palette from site.css. Everything past this point references --vc-* (grounds/
   text/panels) or --rvs-* (accents), never a hard-coded color:
     --vc-bg       full overlay background (gradient + glows)
     --vc-fg       primary text color        (ink in light / cream in dark)
     --vc-fg-rgb   ditto, for rgba chrome (ring/mic borders, captions, toggles)
     --vc-veil-rgb translucent panel base     (warm white in light / ink in dark) */
[data-bs-theme="light"] {
    --vc-bg:
        radial-gradient(1100px 700px at 78% -6%, rgba(var(--rvs-gold-rgb), 0.16), transparent 60%),
        radial-gradient(900px 720px at 6% 14%, rgba(var(--rvs-sage-rgb), 0.13), transparent 55%),
        radial-gradient(1200px 900px at 50% 116%, rgba(var(--rvs-clay-rgb), 0.10), transparent 60%),
        linear-gradient(135deg, var(--rvs-paper) 0%, var(--rvs-paper-2) 60%, var(--rvs-sand) 100%);
    --vc-fg: var(--rvs-ink);
    --vc-fg-rgb: var(--rvs-ink-rgb);
    --vc-veil-rgb: var(--rvs-surface-rgb);
}
[data-bs-theme="dark"] {
    /* "Dark academia" night: forest-charcoal ground with soft gold + teal glows. */
    --vc-bg:
        radial-gradient(900px 600px at 80% 6%, rgba(var(--night-gold-rgb), 0.10), transparent 60%),
        radial-gradient(820px 680px at 8% 100%, rgba(var(--night-teal-rgb), 0.10), transparent 55%),
        linear-gradient(135deg, var(--night-bg) 0%, var(--night-surface) 58%, var(--night-bg-deep) 100%);
    --vc-fg: var(--night-text);
    --vc-fg-rgb: var(--night-text-rgb);
    --vc-veil-rgb: var(--night-surface-rgb);
}

/* Session time-limit countdown badge + notice (colors come from Bootstrap
   .badge / .alert classes; layout only here). */
.voice-timer-wrap {
    margin-top: 0.75rem;
    /* Plain in-flow element — never fixed/absolute so it can't float over neighbors.
       (Direct flex children are blockified, so inline-block here documents intent.)
       flex-shrink: 0 is the load-bearing part: on short viewports (the homepage demo
       iframe) the overlay's flex column squashes shrinkable children, which let the
       timer's box collapse and its text bleed onto the status pill below. Keeping its
       real height makes the overlay scroll instead. */
    display: inline-block;
    position: static;
    flex-shrink: 0;
}

.voice-session-notice {
    max-width: 520px;
    margin: 0 auto 1rem;
    text-align: center;
}

.voice-session-overlay {
    position: fixed;
    top: 46px;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1000;
    /* Width of the Captions ("Live Transcript") side panel — shared with the panel
       itself and the .has-transcript reservations below so they never drift. */
    --vc-transcript-w: 350px;
    /* Height reserved for the fixed bottom control bar (mic wrap + padding). ONE source
       of truth: the hero's bottom padding AND the mobile captions panel's dock both derive
       from it, so as the bar collapses per breakpoint (see the media queries) they track it
       together instead of drifting. Only this variable changes per tier. */
    --vc-bar-h: 220px;
    /* Ground flips with the app theme (paper in light, evergreen dusk in dark) — see --vc-bg above. */
    background: var(--vc-bg);
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Center the hero when it fits; "safe" falls back to top-alignment (instead of clipping
       the top out of reach) when the viewport is too short, and overflow-y lets it scroll.
       The fallback `center` covers the rare browser without the safe keyword (degrades to
       top-aligned, still no overlap). */
    justify-content: center;
    justify-content: safe center;
    color: var(--vc-fg);
    overflow-x: hidden;
    overflow-y: auto;
    /* The control bar is position:fixed at the bottom, so the hero flow ignores it. Reserve
       its height here so the content (avatar → name → status pill) never lands underneath it.
       Trimmed by the max-height queries below (via --vc-bar-h) as the bar shrinks. */
    padding-bottom: var(--vc-bar-h);
}

/* Captions ("Live Transcript") panel open: reserve the panel's width on the right
   so the hero (avatar → name → status → caption) and the fixed control bar shift
   left into the remaining space instead of being overlapped by the fixed panel,
   which used to hover on top on narrower viewports. box-sizing:border-box (Bootstrap
   global) keeps the padding inside the 100% width, so no horizontal overflow.
   Scoped to the same widths where the panel is actually a right-side panel — below
   769px it relocates to the bottom (see the mobile block), so no horizontal reserve. */
@media (min-width: 769px) {
    .voice-session-overlay.has-transcript {
        padding-right: var(--vc-transcript-w);
    }

    /* The control bar is position:fixed (out of the overlay's flow), so its right edge
       must be pulled in explicitly — the overlay's padding doesn't reach it. */
    .voice-session-overlay.has-transcript .voice-control-bar {
        right: var(--vc-transcript-w);
    }
}

/* Demo-session farewell — replaces the graded summary for public-demo users. Reuses the
   themed .voice-session-overlay ground; no fixed control bar here, so drop the reserved
   bottom padding and just center the card. The CTA breaks out of the embed (target="_top"). */
.voice-session-overlay.demo-thanks {
    justify-content: center;
    justify-content: safe center;
    padding: 2rem 1.5rem;
    text-align: center;
}

.demo-thanks-card {
    max-width: 620px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

.demo-thanks-check {
    font-size: 3.2rem;
    line-height: 1;
    color: var(--rvs-sage);
}

.demo-thanks-title {
    font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.3rem);
    font-weight: 600;
    margin: 0;
    color: var(--vc-fg);
}

.demo-thanks-lead {
    font-size: 1.15rem;
    line-height: 1.55;
    margin: 0;
    color: rgba(var(--vc-fg-rgb), 0.92);
}

.demo-thanks-sub {
    font-size: 1rem;
    line-height: 1.55;
    margin: 0;
    color: rgba(var(--vc-fg-rgb), 0.72);
}

.demo-thanks-btn {
    margin-top: 0.75rem;
    display: inline-flex;
    align-items: center;
    padding: 0.85rem 1.6rem;
    border-radius: 999px;
    background: var(--rvs-gold);
    color: var(--rvs-ink);
    font-weight: 600;
    font-size: 1.05rem;
    text-decoration: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.demo-thanks-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(var(--rvs-gold-rgb), 0.4);
    color: var(--rvs-ink);
}

/* "Ask for more sessions" footnote under the CTA */
.demo-thanks-note {
    margin: 1.1rem 0 0;
    font-size: 0.9rem;
    line-height: 1.5;
    color: rgba(var(--vc-fg-rgb), 0.6);
}

.demo-thanks-note a {
    color: var(--rvs-gold);
    text-decoration: underline;
}

/* Startup loader — covers the session overlay until STT is live. Warm evergreen
   translucent veil (brand ink RGB, per the no-hardcoded-color rule) with a blur
   so the avatar reads faintly behind it. Text/spinner inherit the overlay's
   cream color. */
.voice-loading-overlay {
    position: absolute;
    inset: 0;
    z-index: 1200;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(var(--vc-veil-rgb), 0.6);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.voice-loading-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    text-align: center;
    padding: 2rem 2.5rem;
}

.voice-loading-spinner {
    width: 3rem;
    height: 3rem;
    border-width: 0.3em;
}

.voice-loading-title {
    font-size: 1.5rem;
    font-weight: 600;
}

.voice-loading-sub {
    font-size: 1rem;
    opacity: 0.8;
    max-width: 320px;
}

/* Client Avatar */
.voice-avatar-container {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 0.5rem;
}

.voice-avatar-ring {
    width: 260px;
    height: 260px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 4px solid rgba(var(--vc-fg-rgb), 0.2);
    transition: border-color 0.3s ease;
}

.voice-avatar-ring img {
    width: 240px;
    height: 240px;
    border-radius: 50%;
    object-fit: cover;
}

.voice-avatar-ring .avatar-placeholder {
    width: 240px;
    height: 240px;
    border-radius: 50%;
    background: rgba(var(--vc-fg-rgb), 0.1);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 4rem;
    color: rgba(var(--vc-fg-rgb), 0.5);
}

/* Additional-speaker session: extra sims fanned in an arc above the central ring,
   each just touching it and fully visible. Positions are computed inline (percentage
   of the ring box) so the mobile ring resize keeps the fan aligned. */
.voice-avatar-wrap {
    position: relative;
}

/* Reserve headroom so the fan doesn't overlap whatever sits above the avatar. */
.voice-avatar-wrap.has-fan {
    padding-top: 100px;
}

.voice-avatar-wrap .voice-avatar-ring {
    position: relative;
    z-index: 2;
}

.voice-avatar-extra {
    position: absolute;
    transform: translate(-50%, -50%);
    z-index: 3; /* fully visible above the ring */
    width: 96px;
    height: 96px;
    border-radius: 50%;
    overflow: hidden;
    border: 3px solid rgba(var(--vc-fg-rgb), 0.25);
    background: rgba(var(--vc-fg-rgb), 0.1);
    display: flex;
    align-items: center;
    justify-content: center;
}

.voice-avatar-extra img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.voice-avatar-extra .avatar-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2rem;
    color: rgba(var(--vc-fg-rgb), 0.5);
}

/* Group session: all sims the same size, slightly overlapping. */
.voice-avatar-group {
    display: flex;
    align-items: center;
}

.voice-avatar-group .voice-avatar-ring-sm {
    width: 175px;
    height: 175px;
    position: relative;
}

.voice-avatar-group .voice-avatar-ring-sm + .voice-avatar-ring-sm {
    margin-left: -28px;
}

.voice-avatar-group .voice-avatar-ring-sm img,
.voice-avatar-group .voice-avatar-ring-sm .avatar-placeholder {
    width: 160px;
    height: 160px;
    font-size: 2.5rem;
}

.voice-client-name {
    margin-top: 1rem;
    font-size: 1.5rem;
    font-weight: 600;
    text-align: center;
}

.voice-phase-label {
    font-size: 0.9rem;
    color: rgba(var(--vc-fg-rgb), 0.6);
    margin-top: 0.25rem;
}

/* State indicator animations — gold = you (listening), clay = thinking,
   sage = the client (speaking). */
.voice-avatar-ring.state-listening {
    border-color: var(--rvs-gold);
    box-shadow: 0 0 0 0 rgba(var(--rvs-gold-rgb), 0.4);
    animation: pulse-gold 2s infinite;
}

.voice-avatar-ring.state-processing {
    border-color: var(--rvs-clay);
    box-shadow: 0 0 0 0 rgba(var(--rvs-clay-rgb), 0.4);
    animation: pulse-clay 1.5s infinite;
}

.voice-avatar-ring.state-speaking {
    border-color: var(--rvs-sage);
    box-shadow: 0 0 0 0 rgba(var(--rvs-sage-rgb), 0.4);
    animation: pulse-sage 1.8s infinite;
}

@keyframes pulse-gold {
    0% { box-shadow: 0 0 0 0 rgba(var(--rvs-gold-rgb), 0.5); }
    70% { box-shadow: 0 0 0 20px rgba(var(--rvs-gold-rgb), 0); }
    100% { box-shadow: 0 0 0 0 rgba(var(--rvs-gold-rgb), 0); }
}

@keyframes pulse-clay {
    0% { box-shadow: 0 0 0 0 rgba(var(--rvs-clay-rgb), 0.5); }
    70% { box-shadow: 0 0 0 20px rgba(var(--rvs-clay-rgb), 0); }
    100% { box-shadow: 0 0 0 0 rgba(var(--rvs-clay-rgb), 0); }
}

@keyframes pulse-sage {
    0% { box-shadow: 0 0 0 0 rgba(var(--rvs-sage-rgb), 0.5); }
    70% { box-shadow: 0 0 0 20px rgba(var(--rvs-sage-rgb), 0); }
    100% { box-shadow: 0 0 0 0 rgba(var(--rvs-sage-rgb), 0); }
}

/* Status pill — explicit indicator of session state. A regular in-flow element (no
   positioning / z-index): the solid background already keeps decorations passing behind
   it from smearing the text, and staying out of the stacking order means it can never
   float over the fixed control bar below as the viewport height changes. Color shifts
   with state to make "Listening" unmistakable. */
.voice-status-label {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    padding: 0.45rem 1.1rem;
    border-radius: 999px;
    background: rgba(var(--vc-veil-rgb), 0.7);
    border: 1px solid rgba(var(--vc-fg-rgb), 0.18);
    color: rgba(var(--vc-fg-rgb), 0.92);
    min-height: 2.25rem;
    margin-bottom: 2rem;
    box-shadow: 0 2px 8px rgba(var(--vc-veil-rgb), 0.35);
    /* In-flow and never squashed — pairs with .voice-timer-wrap above so the timer and
       this Speaking/Listening pill each keep their full box on short viewports instead
       of overlapping. */
    position: static;
    flex-shrink: 0;
}

.voice-status-label.is-idle {
    visibility: hidden;
}

.voice-status-label.is-listening {
    background: var(--rvs-gold);
    border-color: var(--rvs-gold);
    color: var(--rvs-ink);
}

.voice-status-label.is-processing {
    background: var(--rvs-clay);
    border-color: var(--rvs-clay);
    color: var(--rvs-ink);
}

.voice-status-label.is-speaking {
    background: var(--rvs-sage);
    border-color: var(--rvs-sage);
    color: var(--rvs-ink);
}

.voice-status-label .status-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: currentColor;
    box-shadow: 0 0 8px currentColor;
    animation: status-dot-pulse 1.1s ease-in-out infinite;
}

@keyframes status-dot-pulse {
    0%, 100% { opacity: 0.55; transform: scale(0.85); }
    50% { opacity: 1; transform: scale(1.2); }
}

/* Live STT caption — shows what the user is currently saying */
.voice-interim-caption {
    max-width: min(720px, 90vw);
    margin: -1rem auto 2rem auto;
    padding: 0.75rem 1.25rem;
    border-radius: 12px;
    background: rgba(var(--vc-veil-rgb), 0.6);
    border: 1px solid rgba(var(--vc-fg-rgb), 0.15);
    color: rgba(var(--vc-fg-rgb), 0.92);
    font-size: 1.05rem;
    font-style: italic;
    line-height: 1.4;
    text-align: center;
    animation: caption-fade-in 0.15s ease-out;
}

@keyframes caption-fade-in {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: translateY(0); }
}

/* Bottom control bar — three-column grid so the mic wrap stays exactly
   centered on the page even when the side controls (toggles / end button)
   change width. */
.voice-control-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 1.5rem 2rem;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    column-gap: 2rem;
    background: rgba(var(--vc-veil-rgb), 0.55);
    z-index: 1001;
}

/* Side controls hug the center column rather than the screen edges, so
   they stay visually grouped with the mic on wide screens. */
.voice-control-bar > .voice-toggles { justify-self: end; }
.voice-control-bar > .voice-mic-wrap { justify-self: center; }
.voice-control-bar > .voice-end-controls { justify-self: start; }

.voice-end-controls {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

/* Pause/resume button — gold (brand "hold"); same dimensions as end button so the pair is balanced */
.voice-pause-btn {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: 2px solid var(--rvs-gold);
    background: transparent;
    color: var(--rvs-gold);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    cursor: pointer;
    transition: all 0.2s ease;
}

.voice-pause-btn:hover:not(:disabled) {
    background: var(--rvs-gold);
    color: var(--rvs-ink);
}

.voice-pause-btn:disabled {
    opacity: 0.5;
    cursor: wait;
}

.voice-pause-btn.is-paused {
    background: var(--rvs-gold);
    color: var(--rvs-ink);
}

.voice-toggles {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    color: rgba(var(--vc-fg-rgb), 0.8);
    font-size: 0.95rem;
}

/* Stack each switch over its label (toggle on top, caption centered beneath)
   instead of Bootstrap's side-by-side layout, so the labels line up cleanly
   and the pair stays compact. Reset Bootstrap's label-offset padding and the
   input's negative margin/float that assume a horizontal arrangement. */
.voice-toggles .form-switch {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    padding-left: 0;
    margin-bottom: 0;
}

/* Slightly larger switches than the Bootstrap default so they're easier to hit. */
.voice-toggles .form-check-input {
    width: 2.5em;
    height: 1.25em;
    margin: 0;
    float: none;
    cursor: pointer;
    background-color: rgba(var(--vc-fg-rgb), 0.2);
    border-color: rgba(var(--vc-fg-rgb), 0.3);
}

.voice-toggles .form-check-label {
    cursor: pointer;
    text-align: center;
}

/* Dual-mode label ("PTT / Auto") — always show both modes so it's clear the
   switch toggles between them; the active mode is emphasized. Color is inherited
   from the cream-on-dusk palette above; only opacity/weight vary here. */
.voice-toggles .voice-mode-label {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.voice-toggles .voice-mode-label > span {
    opacity: 0.5;
    transition: opacity 0.15s ease, font-weight 0.15s ease;
}

.voice-toggles .voice-mode-label > span.mode-active {
    opacity: 1;
    font-weight: 700;
}

.voice-toggles .voice-mode-label .mode-sep {
    opacity: 0.35;
    font-weight: 400;
}

.voice-toggles .form-check-input:checked {
    background-color: var(--rvs-gold);
    border-color: var(--rvs-gold);
}

/* Mic button */
.voice-mic-btn {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    border: 3px solid rgba(var(--vc-fg-rgb), 0.3);
    background: rgba(var(--vc-fg-rgb), 0.1);
    color: var(--vc-fg);
    font-size: 1.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;
}

.voice-mic-btn:hover {
    background: rgba(var(--vc-fg-rgb), 0.2);
    border-color: rgba(var(--vc-fg-rgb), 0.5);
}

/* Active = recording: danger red, the conventional "live mic" signal.
   Icon stays light on the red fill in both themes. */
.voice-mic-btn.active {
    background: var(--bs-danger);
    border-color: var(--bs-danger);
    color: var(--rvs-cream);
}

/* The mic button sits inside a wrapper so a sibling canvas can render
   a live waveform ring around it without affecting layout. */
.voice-mic-wrap {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Sized to fit the mic button + its waveform ring without dominating the fixed
       control bar's height (the bar is as tall as this element). */
    width: 160px;
    height: 160px;
}

.voice-mic-wrap .voice-mic-btn {
    position: relative;
    z-index: 1;
}

.voice-mic-viz {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s ease;
}

.voice-mic-viz.active {
    opacity: 1;
}

/* End session button — danger red (destructive). */
.voice-end-btn {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: 2px solid var(--bs-danger);
    background: transparent;
    color: var(--bs-danger);
    font-size: 1.2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;
}

.voice-end-btn:hover {
    background: var(--bs-danger);
    color: var(--rvs-cream);
}

/* Admin transcript panel */
.voice-transcript-panel {
    position: fixed;
    top: 0;
    right: 0;
    width: var(--vc-transcript-w);
    height: 100%;
    background: rgba(var(--vc-veil-rgb), 0.78);
    z-index: 1002;
    display: flex;
    flex-direction: column;
    border-left: 1px solid rgba(var(--vc-fg-rgb), 0.1);
}

.voice-transcript-header {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid rgba(var(--vc-fg-rgb), 0.1);
    font-weight: 600;
    font-size: 0.95rem;
    color: rgba(var(--vc-fg-rgb), 0.9);
}

.voice-transcript-messages {
    flex: 1;
    overflow-y: auto;
    padding: 1rem 1.25rem;
}

.voice-transcript-msg {
    margin-bottom: 0.75rem;
    padding: 0.5rem 0.75rem;
    border-radius: 8px;
    font-size: 0.85rem;
    line-height: 1.4;
}

/* You (the counselor) = gold; the simulated client = sage. */
.voice-transcript-msg.user-msg {
    background: rgba(var(--rvs-gold-rgb), 0.15);
    border-left: 3px solid var(--rvs-gold);
}

.voice-transcript-msg.ai-msg {
    background: rgba(var(--rvs-sage-rgb), 0.15);
    border-left: 3px solid var(--rvs-sage);
}

.voice-transcript-msg .msg-role {
    font-weight: 600;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 0.25rem;
}

.voice-transcript-msg .msg-time {
    font-size: 0.7rem;
    color: rgba(var(--vc-fg-rgb), 0.4);
    float: right;
}

.voice-transcript-msg .msg-text {
    color: rgba(var(--vc-fg-rgb), 0.85);
}

/* Multi-speaker: per-speaker name colors in the live transcript (speaker-0 = primary) */
.voice-transcript-msg .msg-text .speaker-name {
    color: var(--bs-primary);
}

.voice-transcript-msg .msg-text .speaker-name.speaker-1 {
    color: var(--bs-info);
}

.voice-transcript-msg .msg-text .speaker-name.speaker-2 {
    color: var(--bs-success);
}

.voice-transcript-msg .msg-text .speaker-name.speaker-3 {
    color: var(--bs-warning);
}

/* Responsive */
@media (max-width: 768px) {
    .voice-avatar-ring {
        width: 200px;
        height: 200px;
    }

    .voice-avatar-ring img,
    .voice-avatar-ring .avatar-placeholder {
        width: 180px;
        height: 180px;
    }

    .voice-avatar-group .voice-avatar-ring-sm {
        width: 120px;
        height: 120px;
    }

    .voice-avatar-group .voice-avatar-ring-sm + .voice-avatar-ring-sm {
        margin-left: -20px;
    }

    .voice-avatar-group .voice-avatar-ring-sm img,
    .voice-avatar-group .voice-avatar-ring-sm .avatar-placeholder {
        width: 108px;
        height: 108px;
        font-size: 1.75rem;
    }

    .voice-avatar-extra {
        width: 64px;
        height: 64px;
    }

    .voice-avatar-wrap.has-fan {
        padding-top: 70px;
    }

    .voice-client-name {
        font-size: 1.25rem;
    }

    /* Captions dock as a full-width strip pinned directly on top of the control bar.
       bottom == the bar's reserved height (--vc-bar-h), the same value the hero reserves,
       so the panel sits flush above the bar and tracks it as the bar collapses on shorter
       viewports — no more magic offset that drifts out of sync with the bar's height. */
    .voice-transcript-panel {
        width: 100%;
        height: min(40vh, 340px);
        top: auto;
        bottom: var(--vc-bar-h);
        border-left: none;
        border-top: 1px solid rgba(var(--vc-fg-rgb), 0.1);
    }

    /* Collapse the control bar: tighter padding + a smaller mic wrap (the wrap sets the
       bar's height), and shrink the toggles so the whole bar takes less vertical room. */
    .voice-control-bar {
        column-gap: 0.75rem;
        padding: 0.75rem 1rem;
    }

    .voice-toggles {
        gap: 0.6rem;
        font-size: 0.82rem;
    }

    .voice-mic-btn {
        width: 56px;
        height: 56px;
        font-size: 1.25rem;
    }

    .voice-mic-wrap {
        width: 128px;
        height: 128px;
    }

    .voice-end-btn,
    .voice-pause-btn {
        width: 44px;
        height: 44px;
        font-size: 1rem;
    }

    .voice-end-controls {
        gap: 0.5rem;
    }

    /* Collapsed bar ≈ 128 wrap + 24 padding ≈ 152; reserve a little past it. Drives both
       the hero's bottom padding and the captions panel's dock. */
    .voice-session-overlay {
        --vc-bar-h: 166px;
    }
}

/* Short viewports (landscape phones, small/embedded desktop windows, captions sidebar
   squeezing height). The base rule already prevents overlap (safe-center + reserved bar
   padding); these tiers just progressively shrink the avatar + mic so the hero stays
   compact and rarely needs to scroll, and trim the reserved space as the bar shrinks. */
@media (max-height: 720px) {
    .voice-avatar-container {
        margin-bottom: 0.25rem;
    }

    .voice-avatar-ring {
        width: 190px;
        height: 190px;
    }

    .voice-avatar-ring img,
    .voice-avatar-ring .avatar-placeholder {
        width: 172px;
        height: 172px;
    }

    /* Less headroom for the additional-speaker fan since the ring (and fan) are smaller. */
    .voice-avatar-wrap.has-fan {
        padding-top: 66px;
    }

    .voice-status-label {
        margin-bottom: 1rem;
    }

    /* Collapse the control bar on short viewports too: the base 1.5rem padding + 140px wrap
       made the bar taller (~188px) than the space reserved for it, which is what let the
       hero/badge overlap it. Trim the vertical padding only (padding-block) so a narrow +
       short device keeps the width tier's horizontal padding. */
    .voice-control-bar {
        padding-block: 0.9rem;
    }

    .voice-mic-wrap {
        width: 120px;
        height: 120px;
    }

    .voice-mic-btn {
        width: 56px;
        height: 56px;
        font-size: 1.25rem;
    }

    /* Collapsed bar ≈ 120 wrap + 29 padding ≈ 149; reserve past it with headroom. */
    .voice-session-overlay {
        padding-top: 1.5rem;
        --vc-bar-h: 160px;
    }
}

@media (max-height: 590px) {
    .voice-avatar-container {
        margin-bottom: -0.5rem;
    }

    .voice-avatar-ring {
        width: 124px;
        height: 124px;
        border-width: 3px;
    }

    .voice-avatar-ring img,
    .voice-avatar-ring .avatar-placeholder {
        width: 110px;
        height: 110px;
    }

    .voice-avatar-wrap.has-fan {
        padding-top: 44px;
    }

    .voice-client-name {
        font-size: 1.15rem;
    }

    .voice-status-label {
        margin-bottom: 0.5rem;
        padding: 0.3rem 0.9rem;
        font-size: 0.9rem;
    }

    .voice-mic-wrap {
        width: 96px;
        height: 96px;
    }

    .voice-mic-btn {
        width: 48px;
        height: 48px;
        font-size: 1.1rem;
    }

    .voice-control-bar {
        padding-block: 0.5rem;
    }

    .voice-toggles {
        gap: 0.4rem;
        font-size: 0.8rem;
    }

    .voice-end-btn,
    .voice-pause-btn {
        width: 42px;
        height: 42px;
        font-size: 0.9rem;
    }

    /* Fully-collapsed bar ≈ 96 wrap + 16 padding ≈ 112; reserve past it. */
    .voice-session-overlay {
        padding-top: 1rem;
        --vc-bar-h: 122px;
    }
}
