/*
  Console overlay + phone-menu primitives (owner 2026-10-23, demo-school fixes).
  Loaded after bento-grid.css. Structure only - every colour comes from the skin's --theme-* tokens.

  ONE PATTERN for everything that floats:
    - transient notice  -> .bu-toast inside ONE .bu-toast-region, a FIXED stack (owner R-1025-01 item 3, #460): top-right on a
                           desktop, along the bottom on a phone. It never moves the page and never covers a control: while a notice
                           shows, .bu-main reserves the strip the stack sits in. Stacks (max 3), success/info auto-dismiss
                           (errors stay), aria-live.
    - blocking question -> .bu-dialog centered over .bu-dialog-backdrop (focus trap + Esc: bu-dialog.js).
    - detail / edit     -> .bu-drawer, a right-side overlay (bento-grid.css, unchanged).
*/

/* --- Toasts --------------------------------------------------------------------------------- */
.bu-toast-region {
  position: fixed;
  top: 5rem;
  right: var(--structure-gap-lg);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--structure-gap-sm);
  width: min(24rem, calc(100vw - 2 * var(--structure-gap-lg)));
  max-height: calc(100vh - 6rem);
  overflow: hidden;
  box-sizing: border-box;
  pointer-events: none;   /* only the notices themselves take clicks */
}

.bu-toast-region > * {
  pointer-events: auto;
}

/* Reserved space: while a notice is up the page keeps its own strip on the right, so the stack sits over empty space, never a control. */
@media (min-width: 769px) {
  body:has(.bu-toast-region > *) .bu-main {
    padding-right: calc(24rem + 2 * var(--structure-gap-lg));
  }
}

.bu-toast-region:empty {
  display: none;
}

.bu-toast {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--structure-gap-md);
  margin: 0;
  box-sizing: border-box;
}

/* BUG-4 (#420, QA 3ceba79): a toast is also a .bu-panel, which is flex-direction: column with a
   large inset, so the text and the Dismiss button stacked into a ~135px box. A toast is ONE compact row:
   text left, Dismiss right, vertically centred. Same specificity as .bu-panel but later in the cascade. */
.bu-toast.bu-panel {
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--structure-gap-md);
  padding: var(--structure-gap-xs) var(--structure-gap-md);
  width: fit-content;
  min-width: 0;
  max-width: 100%;
}

/* F1: when a toast is scrolled into view the fixed desktop top bar must not cover it. */
.bu-toast {
  scroll-margin-top: 6rem;
}

.bu-toast__text {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.bu-toast__dismiss {
  flex: none;
  min-width: var(--structure-touch-min, 44px);
  min-height: var(--structure-touch-min, 44px);
}

.bu-toast--error {
  border-left: 4px solid var(--theme-state-error, currentColor);
}

.bu-toast--success {
  border-left: 4px solid var(--theme-state-healthy, var(--theme-x-state-info, currentColor));
}

/* --- Blocking dialog -------------------------------------------------------------------------- */
.bu-dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: calc(var(--structure-z-overlay, 50) + 10);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--structure-gap-md);
  box-sizing: border-box;
  background: color-mix(in srgb, var(--theme-bg-canvas, #000) 70%, transparent);
}

.bu-dialog {
  width: min(32rem, 100%);
  max-height: calc(100vh - 2 * var(--structure-gap-md));
  overflow-y: auto;
  box-sizing: border-box;
  background-color: var(--theme-bg-canvas, Canvas);
}

/* A blocking dialog must be opaque: the executive skin gives every .bu-panel a translucent frosted fill (specificity 0,3,0), which made a
   dialog opened over the busy class calendar unreadable (its own text collided with the calendar behind it). This wins by one
   class (and repeats the :hover / :focus-within forms, because a dialog is inside .bu-embedded-page, which clears the fill in those
   states: the focus trap puts focus inside the dialog), and only reads the canvas token, so every skin keeps its own canvas colour. */
:root[data-theme] .bu-dialog-backdrop .bu-dialog.bu-panel,
:root[data-theme] .bu-dialog-backdrop .bu-dialog.bu-panel:hover,
:root[data-theme] .bu-dialog-backdrop .bu-dialog.bu-panel:focus-within {
  background: var(--theme-bg-canvas, Canvas);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  /* .bu-embedded-page also strips a panel's padding and border; a dialog needs both wherever it is opened from. */
  padding: var(--structure-gap-lg);
  border: 1px solid var(--theme-border-active, currentColor);
  border-radius: var(--structure-radius-panel, 8px);
}

/* #491 (found in a real browser at 1440/1024/390): every skin gives the console well (.bu-panel) a frosted backdrop-filter, and a backdrop-filter makes the
   panel the containing block of any position: fixed descendant. So a dialog opened from inside the well was laid out relative to the well (offset, cut off, taller
   than the screen) instead of the viewport. While a dialog is open inside a panel, that panel drops its blur; the dialog's scrim covers it anyway. Structure only. */
:root[data-theme] .bu-panel:has(.bu-dialog-backdrop) {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* ...and the page strips above it (the console's top bar, z-index 10 in the page's own stacking context) used to paint over the top of a dialog on a phone, hiding its
   title. The slab that holds an open dialog rises above them while it is open. */
.bu-slab:has(.bu-dialog-backdrop) {
  z-index: var(--structure-z-overlay, 50);
}

.bu-dialog.bu-dialog--wide {
  width: min(46rem, 100%);
}

.bu-dialog__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--structure-gap-md);
}

.bu-dialog__body {
  display: flex;
  flex-direction: column;
  gap: var(--structure-gap-md);
  margin-top: var(--structure-gap-md);
}

/* --- Phone: toasts full width along the bottom (above the safe area), no horizontal scroll ----- */
@media (max-width: 768px) {
  .bu-toast-region {
    top: auto;
    right: 0;
    left: 0;
    bottom: env(safe-area-inset-bottom, 0px);
    width: 100%;
    max-height: 40vh;
    /* the right side clears the fixed report "?" button, so Dismiss is never under it */
    padding: 0 calc(var(--structure-touch-min, 44px) + 2 * var(--structure-gap-md)) var(--structure-gap-md) var(--structure-gap-md);
  }

  /* Reserved strip at the bottom while a notice shows, so the last control is never under it. */
  body:has(.bu-toast-region > *) .bu-main {
    padding-bottom: calc(10rem + env(safe-area-inset-bottom, 0px));
  }

  .bu-toast,
  .bu-toast.bu-panel {
    max-width: none;
    width: 100%;
  }

  /* Clear the fixed report "?" button so the last control on any page is never under it. */
  .bu-main {
    padding-bottom: calc(var(--structure-touch-min, 44px) + 2 * var(--structure-gap-md));
  }
}

/* --- Toasts and an open overlay (#460 verify, #476 verify) -------------------------------------------------------------
   A drawer (z 50, 360px, right edge) is open: the stack moves to the free bottom-left corner (the page behind the scrim is inert, and the top
   of the left edge is the nav rail). A DIALOG is centred and as tall as the window, so no side of the screen is free at 769-1199px: at EVERY
   width the dialog stops short of a reserved strip along the bottom and the stack sits in that strip (the same rule the phone uses below), so a
   notice and a dialog control can never overlap whatever the width or height. */
@media (min-width: 769px) {
  html:has(.bu-drawer.is-open) .bu-toast-region {
    right: auto;
    left: var(--structure-gap-lg);
    top: auto;
    bottom: var(--structure-gap-lg);
    width: min(20rem, calc(100vw - 360px - 3 * var(--structure-gap-lg)));
  }
}

html:has(.bu-dialog-backdrop) .bu-toast-region {
  top: auto;
  right: 0;
  left: 0;
  bottom: 0;
  width: 100%;
  max-height: 9.5rem;
  overflow-y: auto;
  padding: 0 calc(var(--structure-touch-min, 44px) + 2 * var(--structure-gap-md)) var(--structure-gap-md) var(--structure-gap-md);
}

html:has(.bu-toast-region > *) .bu-dialog-backdrop {
  padding-bottom: calc(10rem + env(safe-area-inset-bottom, 0px));
}

html:has(.bu-toast-region > *) .bu-dialog {
  max-height: calc(100dvh - 12rem - env(safe-area-inset-bottom, 0px));
}

@media (max-width: 768px) {
  html:has(.bu-toast-region > *):has(.bu-drawer.is-open) .bu-toast-region,
  html:has(.bu-toast-region > *):has(.bu-dialog-backdrop) .bu-toast-region {
    max-height: 9.5rem;
    overflow-y: auto;
  }

  html:has(.bu-toast-region > *) .bu-drawer.is-open {
    height: calc(100dvh - 10rem - env(safe-area-inset-bottom, 0px));
    max-height: calc(100dvh - 10rem - env(safe-area-inset-bottom, 0px));
  }

  html:has(.bu-toast-region > *) .bu-dialog-backdrop {
    padding-bottom: calc(10rem + env(safe-area-inset-bottom, 0px));
  }

  html:has(.bu-toast-region > *) .bu-dialog {
    max-height: calc(100dvh - 12rem - env(safe-area-inset-bottom, 0px));
  }
}

/* --- Console phone menu (issue #290) ---------------------------------------------------------- */
.bu-tab-menu-toggle {
  display: none;
}

@media (max-width: 768px) {
  /* Tabs come BEFORE the panel on a phone: left rail = the menu, right rail = a compact row. */
  .bu-console-body > .bu-tab-rail.bu-tab-rail-left {
    order: -2 !important;
  }

  .bu-console-body > .bu-tab-rail.bu-tab-rail-right {
    order: -1 !important;
    flex-direction: row !important;
    flex-wrap: wrap !important;
  }

  .bu-console-body > .bu-tab-rail.bu-tab-rail-right .bu-tab-btn,
  .bu-console-body > .bu-tab-rail.bu-tab-rail-right .bu-tab-rail-stubs {
    width: auto;
  }

  .bu-tab-rail-left > .bu-tab-menu-toggle {
    display: inline-flex;
    width: 100%;
    min-height: var(--structure-touch-min, 44px);
    justify-content: space-between;
  }

  /* Collapsed menu: only the toggle shows. Opening it lists every tab and the Coming soon group. */
  .bu-tab-rail-left:not(.is-menu-open) > :not(.bu-tab-menu-toggle) {
    display: none !important;
  }
}

/* --- Floating help button clearance (phones) ------------------------------------------------------
   The round "?" help button is fixed to the bottom-right corner. On a phone it sat on top of the last control of a long page (the
   calendar's Instructor filter) and of the bottom of a dialog (the waiver sign box). Reserve its height under the console page, and
   keep dialogs clear of that corner. */
@media (max-width: 720px) {
  .bu-main {
    padding-bottom: 4.5rem;
  }

  .bu-dialog-backdrop {
    padding-bottom: calc(var(--structure-gap-md) + 3.5rem);
  }

  .bu-dialog {
    max-height: calc(100vh - 2 * var(--structure-gap-md) - 3.5rem);
  }
}

/* R-1026-01: a side sheet - docked to the right edge at full height; on a phone it is simply full-screen (width 100%). Same blocking dialog, same focus trap. */
.bu-dialog-backdrop:has(.bu-dialog--side) {
  align-items: stretch;
  justify-content: flex-end;
  padding: 0;
}

:root[data-theme] .bu-dialog-backdrop .bu-dialog.bu-panel.bu-dialog--side {
  width: min(42rem, 100%);
  height: 100dvh;
  max-height: 100dvh;
  border-radius: 0;
}

/* --- The student record drawer's five inner tabs (#513, UX sweep 2026-10-26) -------------------------------------------------------
   Structure only, zero colour (the tab colours come from each skin's own .bu-tab-btn recipe, exactly as on the Curriculum page).
   [PILLAR-1: Hick's law / progressive disclosure + the scroll rule R-1026-01] The drawer used to be one 4.4-screen scroll with 23 buttons. It is now a tab row and
   ONE visible pane; the other panes stay mounted but `hidden`, so a half-typed form survives a tab switch and no API call changes.
   [PILLAR-2: WCAG 2.1 AA 1.4.10 reflow] The drawer is 360px wide (a Primer metric, left alone), where five tabs cannot sit on one scrolling line without hiding
   "Waivers" and "Account" off-screen. [PILLAR-1: Miller / scanning] So the drawer's tabs use SHORT words (Overview, Rank, Payments, Waivers, Account; the full name is each tab's
   aria-label + title) and sit on ONE row of equal-growing tabs with tight side padding: it never wraps onto a lonely second line. */
.bu-drawer .bu-subtabs {
  /* The drawer is a column flexbox and the tab row has overflow-y:hidden (ranks.css), so a long pane used to SQUEEZE the row to 36px and clip the tabs (found in the
     real-browser walk: Cara Cole's Rank tab). The row must never shrink. */
  flex: 0 0 auto;
  flex-wrap: nowrap;
  gap: 0;
}

.bu-drawer .bu-subtabs .bu-subtab.bu-control {
  flex: 1 1 auto;
  min-width: 0;
  padding-inline: var(--structure-gap-xs);
}

/* One pane at a time. `display:flex` below would beat the UA's [hidden]{display:none}, so hidden is restated. */
.bu-drawer [data-drawer-pane] {
  display: flex;
  flex-direction: column;
  gap: var(--structure-gap-sm);
  min-width: 0;
}

.bu-drawer [data-drawer-pane][hidden] {
  display: none;
}

/* [PILLAR-3: Fitts's law + one-primary-action] Every pane's first row is a header row (.bu-drawer-header, the family that already exists): the section title
   at the left, the pane's ONE primary button at the right end. In the Overview the first row is the action row itself, so it is pushed to the right too. */
.bu-drawer [data-drawer-pane] > .bu-form-actions:first-child {
  /* row-reverse: the FIRST button in the markup (the primary) is the right-most, and a button that wraps drops under it, still at the right edge. */
  flex-direction: row-reverse;
  justify-content: flex-start;
  margin-top: 0;
}

.bu-drawer [data-drawer-pane] .bu-drawer-header {
  margin-bottom: 0;
}

.bu-drawer [data-drawer-pane] .bu-drawer-header > h4 {
  margin: 0;
}

.bu-drawer [data-drawer-pane] > .bu-form-actions {
  margin-top: var(--structure-gap-xs);
}
