/* The shell is one screen tall. Every pane scrolls inside it, and 100vh always has a 100dvh follow-up: on a phone 100vh is
   the tallest the viewport can get (address bar hidden), so it is only the fallback for browsers without dynamic units. */
.app { min-height: 100%; display: grid; grid-template-columns: var(--nav-w) 1fr; }
.app-nav { position: sticky; top: 0; align-self: start; height: 100vh; height: 100dvh; background: var(--bg); border-right: 1px solid var(--line); display: flex; flex-direction: column; align-items: center; padding: var(--sp-3) 0; gap: var(--sp-2); }
.app-nav .nav-spacer { flex: 1; }
.app-nav .nav-link[aria-current="page"] { background: var(--accent-soft); color: var(--accent); }
.app-main { min-width: 0; }

/* Four zones across: the filters, the queue (its own header above the list), the thread, and the detail panel.
   The two outer ones give up their column as the window narrows — details first, then filters — and come back as
   slide-overs from the same nodes. This file is where that happens, in three steps down from the widest layout. */
.inbox-shell { display: grid; grid-template-columns: var(--rail-w) var(--list-w) minmax(0, 1fr) var(--panel-w); height: 100vh; height: 100dvh; }
/* Positioned so that the visually hidden text (.sr is position: absolute) inside a scrolling pane is contained and clipped by it.
   Without this it is laid out against the page and stretches the document far past the one-screen shell. */
.inbox-shell .pane { position: relative; min-width: 0; overflow: auto; }
/* Exactly one pane is the stage. The nav, filters, queue and detail panel stay on the recessed --bg; the thread rises
   onto --surface and carries the only elevation in the app, so the eye lands on the conversation before it lands on
   the chrome. Elevation used once is elevation that still means something. */
.inbox-shell > .thread-pane { background: var(--surface); box-shadow: var(--lift); z-index: 1; }

/* The filter sidebar. Its sections are the inbox's navigation, so it sits on --bg with the rest of the chrome and
   is separated by a line rather than by a surface of its own. */
.inbox-shell > .filters-pane { display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--sp-3) var(--sp-2); background: var(--bg); border-right: 1px solid var(--line); }
/* The header's Filters button opens the sidebar, so it only exists at the widths where the sidebar is not a column. */
.queue-filters-toggle { display: none; }

/* The queue: a fixed header that never scrolls away, and the list scrolling under it. */
.queue-zone { display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; border-right: 1px solid var(--line); }
.queue-head { flex: none; display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); border-bottom: 1px solid var(--line); }

/* The detail panel, a column here and a slide-over further down. The scrim belongs to the slide-over modes only. */
.inbox-shell > .panel-pane { display: flex; flex-direction: column; background: var(--bg); border-left: 1px solid var(--line); }
/* Dismissed: the agent asked for the width back, and the thread takes it until they ask for the panel again. */
#view-host[data-hidden~="panel"] .inbox-shell { grid-template-columns: var(--rail-w) var(--list-w) minmax(0, 1fr); }
#view-host[data-hidden~="panel"] .inbox-shell > .panel-pane { display: none; }
/* A button that opens a panel already on screen would do nothing, so it only exists while the panel is not a column. */
#view-host:not([data-hidden~="panel"]) .thread-header-top [data-action="details"] { display: none; }
.overlay-scrim { display: none; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.32); z-index: calc(var(--z-panel) - 1); }
#view-host[data-overlay] .overlay-scrim { display: block; }
.panel-head { flex: none; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); padding: var(--sp-3); border-bottom: 1px solid var(--line); }
.panel-title { margin: 0; font-size: var(--fs-lg); font-weight: 600; }

/* Below 1600px the thread is worth more than the panel's 300px, so the panel becomes the slide-over it is on a phone.
   Selected through .inbox-shell so these outweigh the `.inbox-shell .pane { position: relative }` above: a slide-over
   that falls back to relative lands back inside the grid and takes a column again. */
@media (max-width: 1599px) {
  .inbox-shell, #view-host[data-hidden~="panel"] .inbox-shell { grid-template-columns: var(--rail-w) var(--list-w) minmax(0, 1fr); }
  .inbox-shell > .panel-pane, #view-host[data-hidden~="panel"] .inbox-shell > .panel-pane { display: none; position: fixed; top: 0; right: 0; bottom: 0; width: min(var(--panel-w), 100%); box-shadow: var(--shadow); z-index: var(--z-panel); }
  #view-host[data-overlay="panel"] .inbox-shell > .panel-pane { display: flex; }
  #view-host:not([data-hidden~="panel"]) .thread-header-top [data-action="details"] { display: inline-flex; }
}

/* Below 1200px the filter sidebar follows: the list and the thread together need every pixel left. The queue header's
   Filters button is what brings it back, and it only exists at these widths for the same reason the Details one does. */
@media (max-width: 1199px) {
  .inbox-shell { grid-template-columns: var(--list-w) minmax(0, 1fr); }
  .inbox-shell > .filters-pane { display: none; position: fixed; top: 0; left: 0; bottom: 0; width: min(calc(var(--rail-w) + var(--sp-5)), 100%); box-shadow: var(--shadow); z-index: var(--z-panel); }
  #view-host[data-overlay="filters"] .inbox-shell > .filters-pane { display: flex; }
  .queue-filters-toggle { display: inline-flex; }
}

/* The bar and the reconnect banner. The bar only exists on a narrow screen; the banner is shown by realtime.js. */
.mobile-bar { display: none; }

.realtime-banner { position: fixed; top: var(--sp-3); left: 50%; transform: translateX(-50%); z-index: var(--z-toast); max-width: calc(100vw - 2 * var(--sp-4)); padding: var(--sp-2) var(--sp-4); background: var(--surface); color: var(--warn); border: 1px solid var(--warn); border-radius: var(--r-pill); box-shadow: var(--shadow); font-size: var(--fs-sm); }

/* Under 900px one zone shows at a time. The app is exactly one screen tall with the primary nav pinned at the bottom;
   the bar sits on top of the inbox, and the zones scroll inside the space between them. The bar carries only the way
   back out of a conversation — filters ride in the queue header here as everywhere, and the detail panel opens from
   the thread header — so on the list screen it renders nothing and collapses. */
@media (max-width: 899px) {
  .app { height: 100vh; height: 100dvh; min-height: 0; grid-template-columns: 1fr; grid-template-rows: minmax(0, 1fr) var(--nav-w); }
  .app-main { grid-row: 1; grid-column: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; }
  .app-nav { grid-row: 2; grid-column: 1; position: static; align-self: stretch; height: auto; flex-direction: row; border-right: 0; border-top: 1px solid var(--line); padding: 0 var(--sp-2); }
  /* The bottom nav is the one primary touch target row in the mobile layout: every button in it meets the 44px minimum. */
  .app-nav .btn { min-width: 44px; min-height: 44px; }

  .mobile-bar { display: flex; align-items: center; gap: var(--sp-2); height: var(--bar-h); flex-shrink: 0; padding: 0 var(--sp-3); background: var(--surface); border-bottom: 1px solid var(--line); }
  /* On the list screen the bar has nothing to carry: it must take no height rather than sit there as an empty strip. */
  .mobile-bar:empty { display: none; }
  /* 44px, like the bottom nav: the bar is a primary touch row too, and --bar-h (56px) has room for it. */
  .mobile-bar .btn { min-height: 44px; }
  .mobile-bar-title { flex: 1; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .inbox-shell { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); height: auto; flex: 1; min-height: 0; }
  .queue-zone { border-right: 0; }
  /* The queue header is now a primary touch row: .btn's fixed 32px has to give way to the 44px minimum. */
  .queue-head .btn, .panel-head .btn, .thread-header-top .btn { height: auto; min-height: 44px; }
  /* Selected through .queue-head so it outweighs the 32px desktop height in list.css, which loads after this file. */
  .queue-head .queue-search input { min-height: 44px; }
  /* The sidebar is a full-screen list of touch targets here, not a dense column beside the queue: its rows and
     section headings take the same 44px minimum, by the same specificity trick. */
  .filters-pane .filter-row, .filters-pane .filter-section-toggle { min-height: 44px; }
  #view-host[data-pane="list"] .inbox-shell > .thread-pane { display: none; }
  #view-host[data-pane="thread"] .inbox-shell > .queue-zone { display: none; }

  /* Both slide-overs take the whole screen here, between the bar (whose Done button closes them) and the bottom nav.
     At that width there is nothing left of the inbox to see through a scrim, so the scrim does not show. */
  .inbox-shell > .panel-pane, .inbox-shell > .filters-pane { top: var(--bar-h); left: 0; right: 0; bottom: var(--nav-w); width: auto; border-left: 0; border-right: 0; box-shadow: none; }
  #view-host[data-overlay] .overlay-scrim { display: none; }
  /* The zone under the overlay keeps its layout and scroll offset, but must not be reachable by Tab or a screen reader. */
  #view-host[data-overlay] .inbox-shell > :is(.queue-zone, .thread-pane) { visibility: hidden; }

  .realtime-banner { top: calc(var(--bar-h) + var(--sp-2)); }
  /* Toasts sit above the bottom nav, not on top of it. */
  .toast-host { bottom: calc(var(--nav-w) + var(--sp-3)); }
}
