/**
 * Dynamic Viewport Height Fixes
 * Handles iOS Safari address bar, keyboard appearance, etc.
 * 
 * Problem: On mobile browsers, 100vh includes the address bar area,
 * causing content to be hidden behind browser chrome.
 * 
 * Solutions:
 * 1. dvh (dynamic viewport height) - modern browsers
 * 2. --vh CSS variable set by JS - universal fallback
 * 3. -webkit-fill-available - iOS Safari specific
 */

/* ============================================
   FULL HEIGHT UTILITIES
   ============================================ */

/* Standard full height - may have issues on mobile */
.full-height {
  height: 100vh;
}

/* Dynamic full height - best for mobile */
.full-height-dynamic {
  height: 100vh;
  height: 100dvh; /* Dynamic viewport height - adjusts with browser chrome */
}

/* JS-controlled full height (most reliable cross-browser) */
.full-height-js {
  height: calc(var(--vh, 1vh) * 100);
}

/* iOS Safari specific full height */
.full-height-ios {
  height: 100vh;
  height: -webkit-fill-available;
}

/* Safe full height - accounts for safe areas */
.full-height-safe {
  height: calc(100vh - var(--safe-area-top, 0px) - var(--safe-area-bottom, 0px));
  height: calc(100dvh - var(--safe-area-top, 0px) - var(--safe-area-bottom, 0px));
}

/* ============================================
   MIN/MAX HEIGHT UTILITIES
   ============================================ */

.min-full-height {
  min-height: 100vh;
  min-height: 100dvh;
}

.max-full-height {
  max-height: 100vh;
  max-height: 100dvh;
}

/* ============================================
   BODY & HTML VIEWPORT FIXES
   ============================================ */

html {
  /* Prevent iOS bounce scrolling showing background */
  height: 100%;
  overflow: hidden;
}

body {
  /* Use dynamic viewport height where supported */
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

/* iOS Safari specific body fix */
body.is-ios {
  height: 100%;
  height: -webkit-fill-available;
}

/* PWA mode - use full available height */
body.is-pwa {
  height: 100vh;
  height: 100dvh;
  min-height: 100vh;
  min-height: 100dvh;
}

/* ============================================
   SHORT VIEWPORT HANDLING
   When height < 600px (keyboard visible, small device)
   ============================================ */

body.is-short-viewport {
  /* Reduce spacing to fit more content */
  --spacing-scale: 0.75;
}

/* Reduce padding in short viewports */
body.is-short-viewport .p-4 {
  padding: 0.75rem;
}

body.is-short-viewport .p-6 {
  padding: 1rem;
}

body.is-short-viewport .py-4 {
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

body.is-short-viewport .py-6 {
  padding-top: 1rem;
  padding-bottom: 1rem;
}

/* Reduce gaps in short viewports */
body.is-short-viewport .gap-4 {
  gap: 0.5rem;
}

body.is-short-viewport .gap-6 {
  gap: 0.75rem;
}

body.is-short-viewport .space-y-4 > * + * {
  margin-top: 0.5rem;
}

/* ============================================
   RESPONSIVE ACTIVE CALL VIEW (MOBILE)
   ============================================ */

/* Base mobile active call - fluid sizing */
/* Mobile: anchor content to top (flex-start) instead of centering so the
   avatar/details, control grid, Transcribe/Details row, and hangup button
   don't get pushed down toward the bottom-docked #callPanelNav. The fluid
   padding + gap still provide natural breathing room below the header row. */
body.is-mobile #activeCallView {
  padding: clamp(8px, 2vh, 24px) clamp(12px, 3vw, 24px) !important;
  gap: clamp(8px, 2vh, 24px) !important;
  justify-content: flex-start !important;
}

/* Avatar - responsive sizing */
body.is-mobile .active-call-avatar-wrapper > div {
  width: clamp(64px, 18vw, 96px) !important;
  height: clamp(64px, 18vw, 96px) !important;
  font-size: clamp(20px, 5vw, 30px) !important;
}

/* Caller name */
body.is-mobile #activeCallName {
  font-size: clamp(16px, 4.5vw, 20px) !important;
}

/* Caller number */
body.is-mobile #activeCallNumber {
  font-size: clamp(12px, 3vw, 14px) !important;
}

/* Call status */
body.is-mobile #activeCallStatus {
  font-size: clamp(11px, 2.8vw, 14px) !important;
}

/* Timer - responsive */
body.is-mobile #callTimer {
  font-size: clamp(28px, 8vw, 40px) !important;
}

/* Call control buttons grid */
body.is-mobile #activeCallView .grid {
  gap: clamp(6px, 2vw, 12px) !important;
  max-width: clamp(260px, 75vw, 320px) !important;
}

/* Individual call control buttons */
body.is-mobile #activeCallView .grid > button {
  padding: clamp(8px, 2.5vw, 12px) !important;
  border-radius: clamp(10px, 3vw, 16px) !important;
}

body.is-mobile #activeCallView .grid > button i {
  font-size: clamp(16px, 4.5vw, 20px) !important;
}

body.is-mobile #activeCallView .grid > button span {
  font-size: clamp(9px, 2.5vw, 12px) !important;
}

/* Transcription and Details buttons row */
body.is-mobile #activeCallView .flex.gap-3 {
  gap: clamp(6px, 2vw, 12px) !important;
  max-width: clamp(260px, 75vw, 320px) !important;
}

body.is-mobile #activeCallView .flex.gap-3 > button {
  padding: clamp(10px, 3vw, 12px) !important;
  font-size: clamp(12px, 3.2vw, 14px) !important;
}

/* Hangup button */
body.is-mobile #hangupBtn {
  max-width: clamp(260px, 75vw, 320px) !important;
  padding: clamp(12px, 3.5vw, 16px) !important;
  font-size: clamp(14px, 3.5vw, 16px) !important;
}

/* ============================================
   HEIGHT-BASED CALL PANEL ADJUSTMENTS
   ============================================ */

/* Medium height screens (600-700px) */
@media (max-height: 700px) {
  body.is-mobile #activeCallView {
    padding: clamp(6px, 1.5vh, 16px) clamp(10px, 2.5vw, 20px) !important;
    gap: clamp(6px, 1.5vh, 16px) !important;
  }
  
  body.is-mobile .active-call-avatar-wrapper > div {
    width: clamp(56px, min(15vw, 10vh), 80px) !important;
    height: clamp(56px, min(15vw, 10vh), 80px) !important;
    font-size: clamp(18px, 4vw, 24px) !important;
  }
  
  body.is-mobile #callTimer {
    font-size: clamp(24px, min(7vw, 5vh), 32px) !important;
  }
  
  body.is-mobile #activeCallView .grid > button {
    padding: clamp(6px, 2vw, 10px) !important;
  }
  
  body.is-mobile #activeCallView .grid > button i {
    font-size: clamp(14px, 4vw, 18px) !important;
    margin-bottom: 2px !important;
  }
  
  body.is-mobile #activeCallView .grid > button span {
    font-size: clamp(8px, 2.2vw, 11px) !important;
  }
}

/* Short screens (< 600px) - very compact */
@media (max-height: 600px) {
  body.is-mobile #activeCallView {
    padding: 4px 8px !important;
    gap: 4px !important;
  }
  
  body.is-mobile .active-call-avatar-wrapper > div {
    width: clamp(48px, min(12vw, 8vh), 64px) !important;
    height: clamp(48px, min(12vw, 8vh), 64px) !important;
    font-size: clamp(16px, 3.5vw, 20px) !important;
  }
  
  body.is-mobile #activeCallName {
    font-size: clamp(14px, 3.5vw, 16px) !important;
  }
  
  body.is-mobile #activeCallNumber,
  body.is-mobile #activeCallStatus {
    font-size: clamp(10px, 2.5vw, 12px) !important;
  }
  
  body.is-mobile #callTimer {
    font-size: clamp(20px, min(5vw, 4vh), 28px) !important;
  }
  
  body.is-mobile #activeCallView .grid {
    gap: 4px !important;
  }
  
  body.is-mobile #activeCallView .grid > button {
    padding: 4px !important;
    min-height: 44px; /* Keep tappable */
  }
  
  body.is-mobile #activeCallView .grid > button i {
    font-size: clamp(12px, 3.5vw, 16px) !important;
    margin-bottom: 1px !important;
  }
  
  body.is-mobile #activeCallView .grid > button span {
    font-size: clamp(7px, 2vw, 9px) !important;
  }
  
  body.is-mobile #hangupBtn {
    padding: 10px !important;
  }
}

/* Very short screens (< 500px) - minimal UI */
@media (max-height: 500px) {
  body.is-mobile #activeCallView {
    flex-direction: row !important;
    flex-wrap: wrap !important;
    align-content: flex-start !important;
    padding: 4px !important;
    gap: 4px !important;
  }
  
  body.is-mobile #activeCallInfoSection {
    flex-direction: row !important;
    align-items: center !important;
    width: 100% !important;
    gap: 8px !important;
  }
  
  body.is-mobile #activeCallInfoSection > .flex {
    margin-bottom: 0 !important;
    gap: 8px !important;
  }
  
  body.is-mobile .active-call-avatar-wrapper > div {
    width: 40px !important;
    height: 40px !important;
    font-size: 14px !important;
  }
  
  body.is-mobile .active-call-timer-wrapper {
    margin-top: 0 !important;
  }
  
  body.is-mobile #callTimer {
    font-size: 18px !important;
  }
  
  /* 2x5 grid for very short screens */
  body.is-mobile #activeCallView .grid {
    grid-template-columns: repeat(5, 1fr) !important;
    max-width: 100% !important;
  }
  
  body.is-mobile #hangupBtn {
    max-width: 100% !important;
  }
}

/* ============================================
   RESPONSIVE DIALPAD
   Scales based on available viewport space
   ============================================ */

/* Base responsive dialpad - use clamp for fluid sizing */
body.is-mobile .dialpad-container {
  /* Scale container width based on viewport, max 320px */
  max-width: min(320px, calc(100vw - 48px));
  width: 100%;
  padding: 0 8px;
}

body.is-mobile .dialpad-grid {
  /* Fluid gap based on viewport */
  gap: clamp(8px, 3vw, 22px);
}

body.is-mobile .dialpad-btn {
  /* Fluid button size: min 56px, prefer 18vw, max 72px */
  width: clamp(56px, 18vw, 72px);
  height: clamp(56px, 18vw, 72px);
  max-width: clamp(56px, 18vw, 72px);
  max-height: clamp(56px, 18vw, 72px);
  /* Fluid font size */
  font-size: clamp(18px, 5vw, 24px);
}

body.is-mobile .dialpad-letters {
  font-size: clamp(8px, 2.5vw, 10px);
}

body.is-mobile .ios-call-btn {
  /* Scale call button too */
  width: clamp(56px, 18vw, 72px);
  height: clamp(56px, 18vw, 72px);
}

/* Small phones (< 480px width) - ensure dialpad doesn't exceed 320px */
body.is-mobile.bp-xs .dialpad-container {
  max-width: min(320px, calc(100vw - 32px));
}

body.is-mobile.bp-xs .dialpad-grid {
  gap: clamp(6px, 2.5vw, 16px);
}

body.is-mobile.bp-xs .dialpad-btn {
  width: clamp(52px, 17vw, 68px);
  height: clamp(52px, 17vw, 68px);
  max-width: clamp(52px, 17vw, 68px);
  max-height: clamp(52px, 17vw, 68px);
  font-size: clamp(16px, 4.5vw, 22px);
}

/* Short viewport adjustments (keyboard visible, small screen height) */
body.is-short-viewport #dialpadView .dialpad-btn {
  width: clamp(44px, 14vw, 56px);
  height: clamp(44px, 14vw, 56px);
  max-width: clamp(44px, 14vw, 56px);
  max-height: clamp(44px, 14vw, 56px);
  font-size: clamp(14px, 4vw, 18px);
}

body.is-short-viewport #dialpadView .dialpad-grid {
  gap: clamp(4px, 1.5vw, 8px);
}

body.is-short-viewport .dialpad-letters {
  display: none; /* Hide letters to save space */
}

body.is-short-viewport .ios-call-btn {
  width: clamp(44px, 14vw, 56px);
  height: clamp(44px, 14vw, 56px);
}

/* Height-based responsive sizing for dialpad */
/* Use min of width and height-based calculation */
@media (max-height: 700px) {
  body.is-mobile .dialpad-btn {
    width: clamp(52px, min(16vw, 9vh), 68px);
    height: clamp(52px, min(16vw, 9vh), 68px);
    max-width: clamp(52px, min(16vw, 9vh), 68px);
    max-height: clamp(52px, min(16vw, 9vh), 68px);
  }
  
  body.is-mobile .dialpad-grid {
    gap: clamp(6px, min(2vw, 1.5vh), 16px);
  }
  
  body.is-mobile .ios-call-btn {
    width: clamp(52px, min(16vw, 9vh), 68px);
    height: clamp(52px, min(16vw, 9vh), 68px);
  }
}

@media (max-height: 600px) {
  body.is-mobile .dialpad-btn {
    width: clamp(44px, min(14vw, 8vh), 56px);
    height: clamp(44px, min(14vw, 8vh), 56px);
    max-width: clamp(44px, min(14vw, 8vh), 56px);
    max-height: clamp(44px, min(14vw, 8vh), 56px);
    font-size: clamp(14px, 4vw, 18px);
  }
  
  body.is-mobile .dialpad-grid {
    gap: clamp(4px, min(1.5vw, 1vh), 10px);
  }
  
  body.is-mobile .dialpad-letters {
    display: none;
  }
  
  body.is-mobile .ios-call-btn {
    width: clamp(44px, min(14vw, 8vh), 56px);
    height: clamp(44px, min(14vw, 8vh), 56px);
  }
}

/* ============================================
   KEYBOARD VISIBLE STATE
   Added by JS when virtual keyboard is detected
   ============================================ */

body.keyboard-visible {
  /* When keyboard is visible, content area is reduced */
}

body.keyboard-visible .message-input-container {
  /* Adjust for keyboard - remove extra bottom padding */
  padding-bottom: 8px;
}

body.keyboard-visible #conversationsList {
  /* Reduce list height when keyboard is showing */
  max-height: calc(var(--vh, 1vh) * 50);
}

body.keyboard-visible #messageThread {
  /* Message thread should scroll to show input */
  flex: 1;
  min-height: 0;
}

/* Hide non-essential elements when keyboard is visible */
body.keyboard-visible .hide-on-keyboard {
  display: none !important;
}

/* ============================================
   SCROLL BEHAVIOR
   ============================================ */

/* Prevent overscroll bounce on iOS */
body.is-pwa,
body.is-ios.is-pwa {
  overscroll-behavior: none;
  -webkit-overflow-scrolling: touch;
}

/* Smooth scrolling for scrollable containers */
.scroll-container,
#conversationsList,
#messageThread,
#callHistoryList,
#callPanelContactsList,
#callPanelFavoritesList {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* ============================================
   VIEWPORT META TAG SUPPORT
   These styles complement the viewport meta tag:
   <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
   ============================================ */

/* Ensure inputs don't zoom on iOS (font-size >= 16px) */
body.is-ios input[type="text"],
body.is-ios input[type="email"],
body.is-ios input[type="password"],
body.is-ios input[type="tel"],
body.is-ios input[type="number"],
body.is-ios input[type="search"],
body.is-ios textarea,
body.is-ios select {
  font-size: 16px;
}

/* ============================================
   DEBUG MODE - Show viewport info
   Add body.debug-viewport to see viewport dimensions
   ============================================ */

body.debug-viewport::after {
  content: 'vh: ' attr(data-vh) ' | dvh: ' attr(data-dvh) ' | ' attr(data-dimensions);
  position: fixed;
  top: 50px;
  left: 8px;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-family: monospace;
  z-index: 99999;
  pointer-events: none;
}

/* ============================================
   MOBILE HEADER ADJUSTMENTS
   Using body.is-mobile class from layout-state.js
   ============================================ */

/* Presence button sizing across all device types */
/* Desktop/Tablet: auto-size to content (label + chevron visible) */
body.is-desktop #presenceBtn,
body.is-tablet #presenceBtn {
  width: auto;
  height: auto;
  min-width: auto;
  max-width: none;
}

/* Mobile ONLY: uniform header action buttons (48x44) */
/* Using !important to override Tailwind utility classes (px-3, py-2) */
body.is-mobile #presenceBtn,
body.is-mobile #mobileSearchBtn {
  width: 48px !important;
  height: 44px !important;
  min-width: 48px !important;
  max-width: 48px !important;
  padding: 0 !important;
  justify-content: center !important;
}

body.is-mobile #phoneContainer {
  display: none !important;
}

/* Remove the space-x-2 margin when only showing dot */
body.is-mobile #presenceBtn > * {
  margin-left: 0 !important;
}

/* Hide emoji and markdown buttons on mobile */
body.is-mobile #emojiBtn,
body.is-mobile #markdownHintBtn {
  display: none;
}

/* ============================================
   KEYBOARD VISIBLE STATE — NOTES VIEW
   Complements the chat-compose rules at lines 469-490.
   The keyboard-visible class is set by the visualViewport
   listener in layout-state.js init() (added 2026-04-28).
   ============================================ */

body.keyboard-visible .notes-editor-footer {
  /* Suppress word-count / save-indicator bar to reclaim ~40px for editing.
     Note: on mobile the save-indicator chip lives inside this footer (per
     placeSaveIndicator() in notes-module.js); hiding the footer hides the
     chip too — intentional, the user trades save-state visibility for screen
     real estate while typing. Chip reappears on keyboard dismiss. */
  display: none !important;
}

body.keyboard-visible .notes-editor-toolbar {
  /* Tighten padding when vertical space is scarce. */
  padding: 4px 6px;
  gap: 1px;
}

body.keyboard-visible .notes-editor-body {
  /* Remove the large bottom padding designed for desktop viewing. */
  padding-bottom: 8px;
}

/* NOTE: body.style.height is set by the visualViewport handler in
   layout-state.js. The inline style overrides Tailwind h-screen (100vh)
   on mobile, which is intentional: 100vh does not account for the soft
   keyboard; visualViewport.height does. */

/* ============================================
   HTML / VIEWPORT SCROLL LOCK (iOS 15 keyboard pan prevention)
   On iOS 15 WKWebView, focusing an input causes the OS to pan the
   document upward (via documentElement.scrollTop) to position the
   input above the keyboard. The pan happens BEFORE any JS event
   fires, so JS-side compensation always loses the race.
   Root-cause prevention: lock <html> to a fixed-size, overflow:hidden
   box. With no scrollable extent at the html level, iOS's scroll-into-
   view has nowhere to scroll. <body> already has overflow:hidden via
   Tailwind, but <html> is left at default (overflow: visible), which
   is the surface iOS actually pans. Locking both kills the pan.
   Desktop is unaffected (no virtual keyboard, no relevance).
   ============================================ */
@media (max-width: 1023px) {
  html {
    height: 100%;
    overflow: hidden;
    /* Disable any rubber-band / overscroll behavior on the root scroller
       so even momentum scrolls cannot trigger a pan. */
    overscroll-behavior: none;
    /* Anchor element on focus must NOT request scroll-into-view at the
       root level. iOS uses scroll-margin to add buffer when scrolling
       inputs into view; setting it to 0 also signals "no buffer needed". */
    scroll-padding: 0;
  }
}

/* ============================================
   KEYBOARD VISIBLE STATE — CHAT THREAD CONTAINERS
   On mobile-with-conversation-selected, #messageArea is `position: fixed`
   with `height: calc(100vh - 76px) !important` (styles.css:2854). 100vh
   does NOT shrink when the keyboard opens (it tracks the layout viewport,
   not the visual viewport — same on iOS WKWebView and Chromium WebView).
   Result: the message-compose-area at the bottom of #messageArea was
   sitting BELOW the keyboard, hidden.
   .main-content-area has the same problem at styles.css:2151.
   Fix: when body.keyboard-visible is on, swap 100vh for the JS-tracked
   --vh (= vv.height * 0.01) custom property so these fixed/sized
   containers shrink in lockstep with the visual viewport.
   ============================================ */
@media (max-width: 849px) {
  body.keyboard-visible .main-content-area {
    height: calc(var(--vh, 1vh) * 100 - var(--header-height, 76px)) !important;
  }
  body.keyboard-visible .conversation-selected .message-area {
    height: calc(var(--vh, 1vh) * 100 - var(--header-height, 76px)) !important;
  }
  /* iOS Safari -webkit-fill-available shadow rules (styles.css:2273-2276)
     also pin against the layout viewport. Override here too. */
  @supports (-webkit-touch-callout: none) {
    body.keyboard-visible .main-content-area {
      height: calc(var(--vh, 1vh) * 100 - var(--header-height, 76px)) !important;
    }
  }
}

/* ============================================
   Mobile UX: thread-header replaces app-header
   ============================================
   Behind feature flag `mobile_thread_header_replaces_app_header`. When
   the user opens a chat thread on a phone, the global <header> fades
   to opacity 0 and the .thread-header (already inside #messageArea)
   docks at top:0. Reclaims ~58px of vertical space and matches the
   Microsoft Teams mobile pattern.

   Two state classes drive this — they are intentionally split:

     * body.chat-thread-open       — held for the entire in-thread
                                     session. Drives the LAYOUT snap
                                     (#messageArea top:0, sidebar top:0,
                                     thread-header safe-area padding).
                                     Stays on through the back-slide so
                                     the thread doesn't jump 58px down
                                     mid-animation.
     * body.app-header-faded       — drives only the header OPACITY.
                                     Added at the start of the forward
                                     slide and the start of back-slide
                                     it is removed, so the header fade
                                     and the X-slide animate in lockstep
                                     with each other (both 360ms).

   Other gates:
     * body.mobile-thread-replaces-header-enabled  — feature flag fetch.
     * body.chat-thread-active-view                — chat is the active
                                     center view (excludes operatorConsole,
                                     callDetails, meetingAssist).
     * View-exclusions: notes-active, settings-open, contacts-active-*,
       operator-console-popout-mode — so opening those from in-thread
       brings the app header back.
     * @media (max-width: 849px) and (hover: none) and (pointer: coarse)
       so tablets and desktops are never affected.

   Cross-fade design (Microsoft Teams pattern):
     - 360ms cubic-bezier(0.25, 1, 0.5, 1), same as
       playMobileEnterThreadAnimation.
     - Header opacity 1 → 0 with pointer-events: none. The instant
       top-snap on #messageArea (76 → 0) is masked by the still-opaque
       header at frame 0.
     - .conversations-sidebar also moves top:0 → top:0 so the back-slide
       doesn't expose an 18px gap between the fading-in header and the
       sidebar's top edge.
     - .thread-header gets safe-area-inset-top padding only in this mode
       so the iPhone notch doesn't bisect the contact name.
   ============================================ */
@media (max-width: 849px) and (hover: none) and (pointer: coarse) {
  /* Always-on transition + z-index: the transition fires whenever the
     opacity gate flips. z-index keeps the header above #messageArea
     (which is position:fixed and would otherwise paint above static
     ancestors). */
  body.mobile-thread-replaces-header-enabled > header {
    transition: opacity 360ms cubic-bezier(0.25, 1, 0.5, 1);
    will-change: opacity;
    z-index: 50;
  }

  /* Header opacity gate — the JS animation hooks toggle .app-header-faded
     synchronously with the slide kickoff in either direction. View-
     exclusions ensure opening a non-chat view from in-thread brings the
     header back regardless of .app-header-faded's value. */
  body.mobile-thread-replaces-header-enabled.app-header-faded:not(.notes-active):not(.settings-open):not(.contacts-active-mobile):not(.contacts-active-desktop):not(.operator-console-popout-mode) > header {
    opacity: 0;
    pointer-events: none;
  }

  /* Layout gate — held the entire in-thread session, including through
     the back animation, so the thread/sidebar don't snap mid-slide. The
     gate accepts EITHER chat-thread-active-view (chat thread) OR
     contact-detail-active-view (contact detail panel inside #messageArea),
     since both surfaces want their own header docked at top:0 in place
     of the faded app header. callDetails / operatorConsole / meetingAssist
     are NOT included — they have their own internal layouts. */
  body.mobile-thread-replaces-header-enabled.chat-thread-open.chat-thread-active-view:not(.notes-active):not(.settings-open):not(.contacts-active-mobile):not(.contacts-active-desktop):not(.operator-console-popout-mode) #messageArea,
  body.mobile-thread-replaces-header-enabled.chat-thread-open.contact-detail-active-view:not(.notes-active):not(.settings-open):not(.contacts-active-mobile):not(.contacts-active-desktop):not(.operator-console-popout-mode) #messageArea {
    top: 0 !important;
    height: 100vh !important;
    height: calc(var(--vh, 1vh) * 100) !important;
  }
  body.mobile-thread-replaces-header-enabled.chat-thread-open.chat-thread-active-view:not(.notes-active):not(.settings-open):not(.contacts-active-mobile):not(.contacts-active-desktop):not(.operator-console-popout-mode) .conversations-sidebar,
  body.mobile-thread-replaces-header-enabled.chat-thread-open.contact-detail-active-view:not(.notes-active):not(.settings-open):not(.contacts-active-mobile):not(.contacts-active-desktop):not(.operator-console-popout-mode) .conversations-sidebar {
    top: 0 !important;
  }
  /* Thread-header has an inline style="padding-top: 22px; padding-bottom: 22px"
     which we must beat with !important. We add the safe-area-inset-top to the
     existing 22px so the back button + contact name clear the iPhone notch /
     Dynamic Island, while preserving the original visual breathing room. */
  body.mobile-thread-replaces-header-enabled.chat-thread-open.chat-thread-active-view:not(.notes-active):not(.settings-open):not(.contacts-active-mobile):not(.contacts-active-desktop):not(.operator-console-popout-mode) .thread-header {
    padding-top: calc(22px + env(safe-area-inset-top, 0px)) !important;
  }
  /* Contact-detail panel's own header (px-6 py-4 flex justify-between strip
     at the top of #contactDetailPanel) needs the same notch-clearance treatment
     so its avatar+name don't sit under the iPhone notch. The existing
     `py-4` (= 16px) is preserved by adding the safe-area on top. */
  body.mobile-thread-replaces-header-enabled.chat-thread-open.contact-detail-active-view:not(.notes-active):not(.settings-open):not(.contacts-active-mobile):not(.contacts-active-desktop):not(.operator-console-popout-mode) #contactDetailPanel > div:first-child {
    padding-top: calc(16px + env(safe-area-inset-top, 0px)) !important;
  }
}

/* Reduced motion: skip the cross-fade animation, keep the layout swap.
   This matches the existing playMobileEnterThreadAnimation guard. */
@media (prefers-reduced-motion: reduce) {
  body.mobile-thread-replaces-header-enabled > header {
    transition: none !important;
  }
}
