/* ===========================================================================
 * The raised layer — FM05 Select · FB02 Modal · FB03 Menu · FB01 Toast.
 * D29.
 *
 * §6 records that 12 frames contain no drop shadow, and that adding one would
 * look visibly foreign. Every other design system solves "this floats above
 * the page" with a shadow. This one cannot, so it uses three things it already
 * has, and the recipe is identical for all four components:
 *
 *   surface  rgba(44,40,26,0.92)   warm and TINTED, not another white wash —
 *                                  a white wash over a scrim goes muddy grey
 *   blur     24px backdrop-filter  what actually separates it from the page
 *   border   26% white             brighter than any card's 18%
 *
 * Do not add a box-shadow to anything in this file.
 * ======================================================================== */

.ui-raised {
  background: var(--overlay-surface);
  border: var(--border-width) solid var(--border-raised);
  border-radius: var(--radius-md);
  backdrop-filter: blur(var(--overlay-blur));
  -webkit-backdrop-filter: blur(var(--overlay-blur));
}

/* --- FM05 Select --------------------------------------------------------
 * Never a native <select> — banned repo-wide and lint-enforced. The trigger is
 * a button carrying the input's own geometry, and the listbox is a popover.
 * --------------------------------------------------------------------- */
.ui-select { position: relative; }

.ui-select__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  height: var(--control-height);
  padding: 0 var(--space-3);
  background: var(--surface-input);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: var(--type-body-lg-size);
  line-height: var(--type-body-lg-leading);
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--easing-standard);
}

.shell--player .ui-select__trigger { height: var(--control-height-mobile); }

.ui-select__trigger.is-placeholder { color: var(--text-placeholder); }
.ui-select__trigger:hover { border-color: var(--border-raised); }

.ui-select__trigger:focus-visible {
  border-color: var(--gold-100);
  outline: var(--focus-halo-width) solid var(--gold-halo);
  outline-offset: 0;
}

/* Open: the trigger takes the focused border whether or not it has focus, so
   the trigger and its popover read as one object. */
.ui-select__trigger[aria-expanded="true"] {
  border-color: var(--gold-100);
}

.ui-select__chevron {
  color: var(--text-secondary);
  transition: transform var(--duration-fast) var(--easing-standard),
              color var(--duration-fast) var(--easing-standard);
}

.ui-select__trigger[aria-expanded="true"] .ui-select__chevron {
  transform: rotate(180deg);
  color: var(--text-gold);
}

.ui-select__listbox {
  position: absolute;
  z-index: var(--z-popover);
  top: calc(100% + var(--space-2));
  left: 0;
  right: 0;
  padding: var(--overlay-inset);
  max-height: var(--checklist-height);
  overflow-y: auto;
}

.ui-select__listbox[hidden] { display: none; }

.ui-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  height: var(--control-height);
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: var(--type-body-size);
  line-height: var(--type-body-leading);
  color: var(--text-option);
  text-align: left;
  cursor: pointer;
  background: none;
  border: 0;
}

/* Hover and keyboard-active are the SAME wash. Two different highlights in one
   open listbox is the classic way this control gets confusing. */
.ui-option:hover,
.ui-option.is-active { background: var(--surface-hover-item); color: var(--text-primary); }

.ui-option[aria-selected="true"] {
  background: var(--surface-selected);
  color: var(--text-primary);
  font-weight: var(--font-weight-semibold);
}

.ui-option__tick { color: var(--gold-100); opacity: 0; flex: none; }
.ui-option[aria-selected="true"] .ui-option__tick { opacity: 1; }

/* --- FM14 Combobox -------------------------------------------------------
 * FM05's editable sibling (D214): a search field with its matches under it.
 * The rows are .ui-option, the popup is .ui-raised — the same wash, border and
 * blur as every other raised surface — and the field is FM04's search input.
 *
 * Popover on a desktop browser; INLINE below 768px and in the native shells,
 * where the list sits in the page's flow and pushes content down rather than
 * covering it. Decided here, never in Ruby (D31).
 * --------------------------------------------------------------------- */
.ui-combobox { position: relative; display: block; scroll-margin-top: var(--sticky-offset); }

.ui-combobox__form { display: block; }

.ui-combobox__field { display: flex; gap: var(--space-2); align-items: center; }
.ui-combobox__field[hidden] { display: none; }
.ui-combobox__field .ui-search { flex: 1; min-width: 0; }

/* 16px whatever the shell: below 16 iOS zooms the page on focus. */
.ui-combobox__input { font-size: var(--type-body-lg-size); padding-right: var(--space-10); }

.ui-combobox__spinner {
  position: absolute;
  right: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
}
.ui-combobox__spinner[hidden] { display: none; }

.ui-combobox__popup {
  margin-top: var(--space-2);
  padding: var(--overlay-inset);
  padding-bottom: calc(var(--overlay-inset) + env(safe-area-inset-bottom));
}
.ui-combobox__popup[hidden] { display: none; }

.ui-combobox--popover .ui-combobox__popup {
  position: absolute;
  z-index: var(--z-popover);
  top: 100%;
  left: 0;
  right: 0;
  padding-bottom: var(--overlay-inset);
}

@media (min-width: 768px) {
  html:not(.hotwire-native) .ui-combobox--auto .ui-combobox__popup {
    position: absolute;
    z-index: var(--z-popover);
    top: 100%;
    left: 0;
    right: 0;
    padding-bottom: var(--overlay-inset);
  }
}

.ui-combobox__listbox {
  display: flex;
  flex-direction: column;
  max-height: var(--checklist-height);
  overflow-y: auto;
}
.ui-combobox__listbox:empty { display: none; }

/* Inline, the page scrolls instead of the list. */
.ui-combobox--inline .ui-combobox__listbox { max-height: none; }
@media (max-width: 767px) {
  .ui-combobox--auto .ui-combobox__listbox { max-height: none; }
}
.hotwire-native .ui-combobox--auto .ui-combobox__listbox { max-height: none; }

/* Two lines, so the row grows rather than holding FM05's control height. */
.ui-combobox__option {
  height: auto;
  min-height: var(--control-height-mobile);
  padding-top: var(--space-2);
  padding-bottom: var(--space-2);
  justify-content: flex-start;
  gap: var(--space-3);
  text-decoration: none;
}

/* A stale list while the next answer is on its way: muted text, never a
   change of opacity, which belongs to disabled alone (D28). */
.ui-combobox__listbox.is-stale .ui-combobox__option { color: var(--text-muted); }

.ui-combobox__leading { display: inline-flex; flex: none; }
.ui-combobox__text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.ui-combobox__label { color: inherit; overflow-wrap: anywhere; }
.ui-combobox__label mark { background: none; color: var(--text-primary); font-weight: var(--font-weight-semibold); }
.ui-combobox__secondary {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: var(--text-secondary);
  font-weight: var(--font-weight-regular);
}
.ui-combobox__tag {
  flex: none;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: var(--text-gold);
}

.ui-combobox__message {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3);
  font-size: var(--type-body-size);
  line-height: var(--type-body-leading);
  color: var(--text-secondary);
}
.ui-combobox__message[hidden] { display: none; }
/* Brick text only (D27). */
.ui-combobox__message--error { color: var(--danger-text); }

.ui-combobox__retry {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--text-gold);
  text-decoration: underline;
  cursor: pointer;
}
.ui-combobox__retry:focus-visible { outline: var(--focus-ring-outline); outline-offset: var(--focus-ring-offset); outline-color: var(--focus-colour-neutral); }

/* THE CHOSEN CLUB. The field's own geometry, so nothing below it moves. */
.ui-combobox__chip {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--control-height-mobile);
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3);
  background: var(--surface-selected);
  border: var(--border-width) solid var(--border-raised);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
}
.ui-combobox__chip[hidden] { display: none; }
.ui-combobox__chip .ui-combobox__label { font-weight: var(--font-weight-semibold); }
.ui-combobox__chip .ui-combobox__secondary:empty { display: none; }

.ui-combobox__clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--control-height);
  height: var(--control-height);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  cursor: pointer;
}
.ui-combobox__clear:hover { background: var(--surface-hover-item); color: var(--text-primary); }
.ui-combobox__clear:focus-visible { outline: var(--focus-ring-outline); outline-offset: var(--focus-ring-offset); outline-color: var(--focus-colour-neutral); }

.ui-combobox.is-disabled .ui-combobox__chip { opacity: var(--opacity-disabled); }

/* --- FB03 Menu — the hamburger panel. Drawn on all 12 mocks, opened on
       none of them; this is what it opens. -------------------------------- */
.ui-menu {
  position: absolute;
  z-index: var(--z-popover);
  width: var(--menu-width);
  padding: var(--overlay-inset);
  display: flex;
  flex-direction: column;
}

.ui-menu-root { position: relative; }

.ui-menu--start { left: 0; }
.ui-menu--end { right: 0; }
.ui-menu { top: calc(100% + var(--space-2)); }

/* Opens upward, for a trigger pinned to the foot of the window (D176). */
.ui-menu--above { top: auto; bottom: calc(100% + var(--space-2)); }

.ui-menu[hidden] { display: none; }

.ui-menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: var(--control-height);
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--type-body-size);
  line-height: var(--type-body-leading);
  color: var(--text-option);
  text-decoration: none;
  cursor: pointer;
  background: none;
  border: 0;
  font-family: var(--font-sans);
  text-align: left;
  width: 100%;
}

.ui-menu__item:hover,
.ui-menu__item.is-hover { background: var(--surface-hover-item); color: var(--text-primary); text-decoration: none; }
.ui-menu__item:focus-visible,
.ui-menu__item.is-focus { outline: var(--focus-ring-outline); outline-offset: var(--focus-ring-offset); outline-color: var(--focus-colour-neutral); }

.ui-menu__item.is-active,
.ui-menu__item[aria-current="page"] {
  background: var(--surface-selected);
  color: var(--text-primary);
  font-weight: var(--font-weight-semibold);
}

/* A POST item (`method:`) is a `button_to` form around the button. The form
   contributes no box of its own, so the button is a flex child of the panel
   exactly as a link item is, and the two cannot drift apart in size. */
.ui-menu__form { display: contents; }

/* The labelled trigger (`trigger_text:`) — the admin top bar's account menu
   for a multi-role account (D144). It reads as the plain Account link it
   stands in for, plus a chevron, so a person with one role and a person with
   three see the same control in the same place. Hover changes the fill, never
   the opacity (D28); focus is the neutral ring, drawn with `outline` (D30). */
.ui-menu__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-secondary);
  font-family: var(--font-sans);
  font-size: var(--type-caption-size);
  cursor: pointer;
  transition: color var(--duration-fast) var(--easing-standard),
              background-color var(--duration-fast) var(--easing-standard);
}

.ui-menu__trigger:hover,
.ui-menu__trigger.is-hover,
.ui-menu__trigger[aria-expanded="true"] {
  background: var(--surface-hover-item);
  color: var(--text-primary);
}

/* A trigger whose contents are the caller's (the rail's identity block): full
   width of its slot, left-aligned, body-sized text. */
.ui-menu__trigger--custom {
  width: 100%;
  gap: var(--space-3);
  text-align: left;
  font-size: var(--type-body-size);
}

.ui-menu__trigger:focus-visible,
.ui-menu__trigger.is-focus {
  outline: var(--focus-ring-outline);
  outline-offset: var(--focus-ring-offset);
  outline-color: var(--focus-colour-neutral);
}


/* --- FB02 Modal --------------------------------------------------------- */
/* `position: fixed; inset: 0` rather than `width: 100%; height: 100%`. A
   <dialog> in the top layer has the viewport as its containing block, so the
   percentages ought to work — but they resolve against a box the UA sizes to
   fit-content by default, and the panel inside collapsed to 50px wide in
   testing. Insetting to all four edges does not depend on that resolution. */
.ui-modal {
  position: fixed;
  inset: 0;
  margin: 0;
  border: 0;
  padding: 0;
  background: none;
  width: auto;
  height: auto;
  max-width: none;
  max-height: none;
  overflow: auto;
}

.ui-modal::backdrop {
  background: var(--scrim);
  backdrop-filter: blur(var(--scrim-blur));
  -webkit-backdrop-filter: blur(var(--scrim-blur));
}

.ui-modal__positioner {
  min-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
}

.ui-modal__panel {
  width: 100%;
  max-width: var(--modal-width);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.ui-modal__title {
  font-size: var(--type-h2-size);
  line-height: var(--type-h2-leading);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
}

.ui-modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
}

/* --- FB01 Toast ---------------------------------------------------------
 * Bottom-centre, auto-dismissing. Semantic toasts take a TINTED body of their
 * own rather than the neutral overlay surface — at 14px on a blurred panel the
 * border alone does not carry the difference between "sent" and "failed".
 * --------------------------------------------------------------------- */
.ui-toast-region {
  position: fixed;
  z-index: var(--z-toast);
  left: 50%;
  bottom: calc(var(--space-6) + var(--native-inset-bottom));
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: 100%;
  max-width: var(--shell-player-width);
  padding: 0 var(--space-5);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  pointer-events: none;
}

.ui-toast {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  font-size: var(--type-body-size);
  line-height: var(--type-body-leading);
  color: var(--text-primary);
  pointer-events: auto;
}

.ui-toast__message { flex: 1; }

.ui-toast__action {
  flex: none;
  font-weight: var(--font-weight-semibold);
  color: var(--text-gold);
  background: none;
  border: 0;
  font-family: var(--font-sans);
  font-size: var(--type-body-size);
  cursor: pointer;
}

.ui-toast--neutral .icon { color: var(--text-gold); }
.ui-toast--success { background: var(--success-surface); border-color: var(--success-border); }
.ui-toast--success .icon { color: var(--success); }
.ui-toast--danger { background: var(--danger-surface); border-color: var(--danger-border); }
.ui-toast--danger .icon { color: var(--danger); }

/* The region stacks bottom-anchored, so an appended toast lands nearest the
   bottom edge — closest to a thumb on the player surface, and closest to where
   the eye last was on the admin one. `pointer-events: none` on the region and
   `auto` on each toast means the gap between stacked toasts does not swallow
   clicks on the page underneath. */
@media (prefers-reduced-motion: no-preference) {
  .ui-toast {
    animation: ui-toast-in var(--duration-base) var(--easing-standard);
  }

  .ui-toast.is-leaving {
    animation: ui-toast-out var(--duration-base) var(--easing-standard) forwards;
  }
}

/* Under reduced motion the toast still has to leave. `is-leaving` collapses it
   immediately rather than animating, and toast_controller's fallback timer
   removes it either way — an animation that never runs never fires
   `animationend`. */
@media (prefers-reduced-motion: reduce) {
  .ui-toast.is-leaving { display: none; }
}

@keyframes ui-toast-in {
  from { opacity: 0; transform: translateY(var(--space-3)); }
  to { opacity: 1; transform: none; }
}

@keyframes ui-toast-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(var(--space-3)); }
}
