/* Task33 Batch 1A — Design System + Global App Shell Foundation.

   New, additive component styles only: the header's mobile nav toggle and account dropdown. Loaded
   after static/css/common/layout.css (see templates/layout/base.html) and reuses its tokens
   (--color-*, --space-*, --radius-*, --shadow-dropdown, --z-overlay/--z-dropdown) rather than
   introducing a parallel set, per the specification's "no new color/typography/spacing/component
   system when an approved one already exists" rule (docs/specs/Task33_UI_UX_Specification.md §6.3).

   Batch 1A's scope was limited to what it actually shipped: toasts, a generic business/system error
   dialog, and loading/submit-guard styles were deferred to Batch 1B, added below. Standardized tabs,
   buttons, forms, badges, cards, and tables remain Batch 1C work. */

/* ---------------------------------------------------------------------------------------------------
   Header: left cluster (mobile nav toggle + brand)
   --------------------------------------------------------------------------------------------------- */

.site-header-start {
  align-items: center;
  display: flex;
  gap: var(--space-3);
  min-width: 0;
}

/* The V1 desktop/tablet sidebar is persistent and not collapsible (specification §7.1), so the toggle
   only needs to exist below the 48rem breakpoint. Its `display: none` base and the <=48rem
   `display: inline-flex` override both live together in layout.css (next to .sidebar-backdrop's own
   base-hide rule) -- not here -- because this file loads after layout.css: an unconditional `display`
   declared in this file would win the cascade over layout.css's media-query override at every viewport,
   permanently hiding the toggle even on mobile. (This is exactly the bug that shipped originally: a
   `display: none` was declared here, unconditionally, defeating the mobile override.) */
.header-nav-toggle {
  align-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: #fff;
  cursor: pointer;
  flex: none;
  height: var(--control-height);
  justify-content: center;
  padding: 0;
  width: var(--control-height);
}

.header-nav-toggle:hover,
.header-nav-toggle:focus-visible {
  background: rgb(255 255 255 / 10%);
}

.header-nav-toggle-icon-close {
  display: none;
}

.header-nav-toggle-icon-open svg,
.header-nav-toggle-icon-close svg {
  height: var(--icon-size-nav);
  width: var(--icon-size-nav);
}

.header-nav-toggle[aria-expanded="true"] .header-nav-toggle-icon-open {
  display: none;
}

.header-nav-toggle[aria-expanded="true"] .header-nav-toggle-icon-close {
  display: block;
}

/* ---------------------------------------------------------------------------------------------------
   Header: right-side utility cluster (language + account), see templates/layout/header.html
   --------------------------------------------------------------------------------------------------- */

.site-header-end {
  align-items: center;
  display: flex;
  flex: none;
  gap: var(--space-3);
}

/* Client clock (HH:mm, browser-local): same control height as the flag and avatar so it centres on that row.
   The [hidden] rule is needed because display: flex would otherwise override the hidden attribute. */
.header-clock {
  align-items: center;
  color: #fff;
  display: flex;
  flex: none;
  font-size: 1rem;
  /* Fixed-width digits so the seconds ticking over never shift the header. */
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  gap: var(--space-1);
  height: var(--control-height);
  line-height: 1;
  white-space: nowrap;
}
.header-clock[hidden] {
  display: none;
}
/* Phones: the brand wraps and the account controls need the room, so the clock yields and the flag, avatar and
   name stay. The time is still visible on tablet and desktop widths. */
@media (max-width: 30rem) {
  .header-clock {
    display: none;
  }
  /* The brand (never wrapped) and the account chip do not fit side by side in a 375px header: the avatar stands for the account and the name stays
     available to assistive technology (visually hidden, not display: none), so the two never overlap. */
  .header-account-name {
    block-size: 1px;
    clip-path: inset(50%);
    inline-size: 1px;
    max-width: none;
    overflow: hidden;
    position: absolute;
  }
  .site-header {
    gap: var(--space-2);
    padding-inline: var(--space-4);
  }
  .site-header-start,
  .site-header-end {
    gap: var(--space-2);
  }
  .header-account-trigger {
    padding-inline: var(--space-1);
  }
}
.header-clock-icon {
  color: #cfdbe8;
  display: inline-flex;
  flex: none;
}
.header-clock-icon svg {
  height: 0.9375rem;
  width: 0.9375rem;
}

/* Global Task33 header redesign: a compact flag trigger immediately left of the account avatar,
   opening a popover built the same way as .header-account-menu (hidden-attribute driven; see
   static/js/common/header-account.js, which also keeps this and .header-account mutually exclusive). */
.header-language {
  flex: none;
  position: relative;
}

.header-language-trigger {
  align-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  display: flex;
  height: var(--control-height);
  justify-content: center;
  padding: 0;
  width: var(--control-height);
}

.header-language-trigger:hover,
.header-language-trigger:focus-visible {
  background: rgb(255 255 255 / 10%);
}

.header-language-flag {
  font-size: 1.25rem;
  line-height: 1;
}

.header-language-menu {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-dropdown);
  margin-top: var(--dropdown-gap);
  min-width: 11rem;
  overflow: hidden;
  position: absolute;
  right: 0;
  top: 100%;
  z-index: var(--z-dropdown);
}

.header-language-option {
  align-items: center;
  color: var(--color-text);
  display: flex;
  font-size: 0.875rem;
  font-weight: 600;
  gap: var(--space-3);
  padding: var(--space-3);
  text-decoration: none;
}

.header-language-option:hover,
.header-language-option:focus-visible {
  background: var(--color-surface-muted);
}

.header-language-option-flag {
  flex: none;
  font-size: 1.125rem;
  line-height: 1;
}

.header-language-option-label {
  flex: 1;
}

/* Selected-state indicator: a circle on every row. Inactive is an outlined empty circle; the active locale is
   filled blue with a white check. Both rows share the same height, so the indicator never changes row size. */
.header-language-option-indicator {
  align-items: center;
  background: var(--color-surface);
  border: 1.5px solid var(--color-border-strong);
  border-radius: 50%;
  box-sizing: border-box;
  color: #fff;
  display: flex;
  flex: none;
  height: 1.25rem;
  justify-content: center;
  width: 1.25rem;
}
.header-language-option-indicator.is-active {
  background: var(--color-primary);
  border-color: var(--color-primary);
}
.header-language-option-indicator svg {
  height: 0.75rem;
  stroke-width: 2.4;
  width: 0.75rem;
}

.header-account {
  flex: none;
  position: relative;
}

.header-account-trigger {
  align-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: #fff;
  cursor: pointer;
  display: flex;
  font: inherit;
  gap: var(--space-2);
  height: var(--control-height);
  padding: var(--space-1) var(--space-2);
}

.header-account-trigger:hover,
.header-account-trigger:focus-visible {
  background: rgb(255 255 255 / 10%);
}

.header-account-initial {
  align-items: center;
  background: var(--color-primary);
  border-radius: 50%;
  color: #fff;
  display: flex;
  flex: none;
  font-size: 0.8125rem;
  font-weight: 700;
  height: 1.75rem;
  justify-content: center;
  width: 1.75rem;
}

.header-account-name {
  font-size: 0.875rem;
  font-weight: 700;
  max-width: 10rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.header-account-chevron {
  color: #9fb3c8;
  display: inline-flex;
  flex: none;
  transition: transform 0.15s ease-in-out;
}
.header-account-chevron svg {
  height: var(--icon-size-sm);
  width: var(--icon-size-sm);
}

.header-account-trigger[aria-expanded="true"] .header-account-chevron {
  transform: rotate(180deg);
}

/* Visibility is driven by the `hidden` attribute (static/js/common/header-account.js toggles it), not
   display, so the dropdown degrades to "always hidden" if JavaScript fails to load rather than ever
   being stuck open. */
.header-account-menu {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-dropdown);
  margin-top: var(--dropdown-gap);
  min-width: 12rem;
  overflow: hidden;
  position: absolute;
  right: 0;
  top: 100%;
  z-index: var(--z-dropdown);
}

.header-account-logout {
  align-items: center;
  background: transparent;
  border: 0;
  color: var(--color-text);
  cursor: pointer;
  display: flex;
  font: inherit;
  font-weight: 600;
  gap: var(--space-3);
  padding: var(--space-3);
  text-align: left;
  width: 100%;
}

.header-account-logout-icon {
  align-items: center;
  display: flex;
  flex: none;
  justify-content: center;
}
.header-account-logout-icon svg {
  height: var(--icon-size-nav);
  width: var(--icon-size-nav);
}

.header-account-logout:hover,
.header-account-logout:focus-visible {
  background: var(--color-surface-muted);
}

/* ---------------------------------------------------------------------------------------------------
   Mobile sidebar drawer backdrop (opened/closed state lives on .sidebar/.sidebar-backdrop in
   layout.css's <=48rem media query; this file only needs the always-hidden default, defined there so
   it sits next to the rule that un-hides it).
   --------------------------------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------------------------------
   Task33 Batch 1B: global success/warning toast (layout/toast.html, static/js/common/toast.js)
   --------------------------------------------------------------------------------------------------- */

.toast-region {
  bottom: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: 24rem;
  position: fixed;
  right: var(--space-5);
  z-index: var(--z-toast);
}
.toast {
  align-items: flex-start;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-dropdown);
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
}
.toast--success {
  border-color: #a6e9bf;
}
.toast--success .toast-icon {
  color: var(--color-success);
}
.toast--warning {
  border-color: #f5cc72;
}
.toast--warning .toast-icon {
  color: var(--color-warning);
}
.toast-icon {
  flex: none;
  padding-top: 0.125rem;
}
.toast-message {
  color: var(--color-text);
  flex: 1;
  font-size: 0.875rem;
  margin: 0;
}
/* Optional text action on a toast (Retry after a failed AJAX list load). */
.toast-action {
  background: transparent;
  border: 0;
  color: var(--color-primary);
  cursor: pointer;
  flex: none;
  font-size: 0.875rem;
  font-weight: 700;
  padding: var(--space-1) var(--space-2);
  text-decoration: underline;
}
.toast-close {
  background: transparent;
  border: 0;
  color: var(--color-muted);
  cursor: pointer;
  flex: none;
  padding: var(--space-1);
}
.toast-close:hover,
.toast-close:focus-visible {
  color: var(--color-text);
}

/* ---------------------------------------------------------------------------------------------------
   Task33 Batch 1B: shared business/system error dialog (layout/feedback-dialog.html,
   static/js/common/feedback-dialog.js). Reuses the native <dialog> reset from .confirmation-dialog
   rather than inventing a second one.
   --------------------------------------------------------------------------------------------------- */

.feedback-dialog {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 1.5rem 3rem rgb(16 42 67 / 24%);
  color: var(--color-text);
  max-width: min(28rem, calc(100% - 2 * var(--space-4)));
  padding: 0;
  width: 100%;
}
.feedback-dialog::backdrop {
  background: rgb(11 32 53 / 52%);
}
.feedback-dialog__content {
  padding: var(--space-5);
  text-align: center;
}
.feedback-dialog__icon {
  color: var(--color-danger);
  display: inline-flex;
  margin-bottom: var(--space-3);
}
.feedback-dialog__content h2 {
  margin-bottom: var(--space-2);
}
.feedback-dialog__content p {
  color: var(--color-muted);
  margin-bottom: var(--space-5);
}
.feedback-dialog__list {
  color: var(--color-text);
  display: grid;
  gap: var(--space-1);
  list-style: disc;
  margin: 0 0 var(--space-5);
  padding-inline-start: var(--space-5);
  text-align: start;
}
.feedback-dialog__list[hidden] {
  display: none;
}
.feedback-dialog__content p:has(+ .feedback-dialog__list:not([hidden])) {
  margin-bottom: var(--space-3);
}
.feedback-dialog__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: center;
}

/* Validation summary variant (missing required fields): compact, left-aligned, icon and title on one row, the
   missing fields grouped in a light error panel and the single action at the bottom right. Applied by the server
   when it supplies missingFields and by feedback-dialog.js when it is shown with a list of items; business-error and
   system-error dialogs keep the centred layout above. */
.feedback-dialog--validation {
  max-width: min(29.5rem, calc(100% - 2 * var(--space-4)));
}
.feedback-dialog--validation .feedback-dialog__content {
  padding: var(--space-4) var(--space-5);
  text-align: start;
}
.feedback-dialog--validation .feedback-dialog__header {
  align-items: center;
  display: flex;
  gap: 0.75rem;
  margin-bottom: var(--space-1);
}
.feedback-dialog--validation .feedback-dialog__icon {
  flex: none;
  margin: 0;
}
.feedback-dialog--validation .feedback-dialog__icon svg {
  height: 1.75rem;
  width: 1.75rem;
}
.feedback-dialog--validation .feedback-dialog__content h2 {
  font-size: 1.25rem;
  line-height: 1.3;
  margin: 0;
}
.feedback-dialog--validation .feedback-dialog__content p {
  font-size: 0.9375rem;
  margin: 0 0 var(--space-3);
}
.feedback-dialog--validation .feedback-dialog__list {
  background: #fff5f5;
  border: 1px solid #f3c4c4;
  border-radius: var(--radius-sm, 0.375rem);
  gap: 0.375rem;
  list-style: none;
  margin: 0 0 var(--space-4);
  max-height: 40vh;
  overflow-y: auto;
  padding: 0.625rem 0.75rem;
}
.feedback-dialog--validation .feedback-dialog__list li {
  align-items: baseline;
  display: flex;
  gap: 0.625rem;
}
.feedback-dialog--validation .feedback-dialog__list li::before {
  background: var(--color-danger);
  border-radius: 999px;
  content: "";
  flex: none;
  height: 0.4375rem;
  transform: translateY(-0.1rem);
  width: 0.4375rem;
}
.feedback-dialog--validation .feedback-dialog__actions {
  justify-content: flex-end;
}

/* ---------------------------------------------------------------------------------------------------
   Task33 Batch 1B: opt-in duplicate-submit guard (static/js/common/submit-guard.js). Reuses the
   existing .button:disabled treatment (layout.css); only the busy indicator is new.
   --------------------------------------------------------------------------------------------------- */

.button[aria-busy="true"] {
  cursor: wait;
}

/* ---------------------------------------------------------------------------------------------------
   Task33 Batch 1B: 403/404/500 error pages (templates/error/*.html)
   --------------------------------------------------------------------------------------------------- */

.error-page {
  align-items: center;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: var(--space-8) auto;
  max-width: 28rem;
  text-align: center;
}
/* The icon is 48px inside its round muted background (the circle grows with it: 80px), centred above the heading with 20px between the
   circle and the heading (the 12px flex gap plus 8px of margin). */
.error-page-icon {
  align-items: center;
  background: var(--color-surface-muted);
  border-radius: 50%;
  color: var(--color-muted);
  display: flex;
  height: 5rem;
  justify-content: center;
  margin-bottom: calc(1.25rem - var(--space-3));
  width: 5rem;
}
.error-page-icon svg {
  flex: none;
  height: 3rem;
  width: 3rem;
}
.error-page p {
  color: var(--color-muted);
  margin: 0;
}

/* Workflow breadcrumb (layout/breadcrumb.html :: crumbs): a long trail wraps instead of overflowing, and a parent the user
   cannot open reads as plain, muted text. */
.breadcrumb {
  flex-wrap: wrap;
  row-gap: var(--space-1);
}
.breadcrumb-root {
  color: var(--color-primary);
  font-weight: 600;
}
.breadcrumb-text {
  color: var(--color-muted);
  font-weight: 600;
}

/* Table row actions (shared by the Front Desk tables, Check-in Find Reservation / landing and the Reservation List): the
   Action header and its cells share one horizontal centre, and every row action button has one width whatever its label
   (Review / Check in / View / Select, in either language). Size, padding, font and radius come from .button. */
/* "No." column (layout/table :: noHeader / noCell): compact sequence number, centred, header and values alike. The
   selector is table-qualified so it beats a page's own th/td padding rules wherever it is used. */
table th.table-no-column,
table td.table-no-column {
  font-variant-numeric: tabular-nums;
  min-width: 3.25rem;
  padding-left: var(--space-3);
  padding-right: var(--space-3);
  text-align: center;
  width: 3.25rem;
}
.table-action-column {
  text-align: center;
}
.table-row-action {
  justify-content: center;
  text-align: center;
  white-space: nowrap;
  width: 7rem;
}

/* Task33 shared pager and sortable column header (templates/layout/table.html :: pager / sortColumn). Separate square
   controls with a small gap, icon-only Previous/Next, the active page filled and the unavailable direction muted with no
   hover feedback; sort headers are one link of label plus state icon. First used by the Guest List and the Guest
   Reservation History. */
.table-pager {
  gap: var(--space-1);
}
.table-pager .pagination__segment {
  border-radius: var(--radius-sm);
  padding: 0 var(--space-2);
}
.table-pager .pagination__segment + .pagination__segment {
  border-left: 1px solid var(--color-border-strong);
}
.table-pager .pagination__segment--icon {
  padding: 0;
  width: var(--control-height);
}
.table-pager svg {
  flex: none;
  height: 1rem;
  width: 1rem;
}
.table-pager__prev svg {
  transform: scaleX(-1);
}
.table-pager .pagination__segment--disabled {
  background: var(--color-surface-muted);
  border-color: var(--color-border);
  color: var(--color-muted);
  cursor: not-allowed;
}
.table-pager .pagination__segment--disabled:hover {
  background: var(--color-surface-muted);
  color: var(--color-muted);
}
.table-sort {
  align-items: center;
  border-radius: var(--radius-sm);
  color: inherit;
  cursor: pointer;
  display: inline-flex;
  gap: var(--space-2);
  text-decoration: none;
  /* A sortable header never wraps (label and sort icon stay on one line); a table wider than its card scrolls inside .table-wrap instead. */
  white-space: nowrap;
}
.table-sort:hover .table-sort__label {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.table-sort:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
.table-sort__label {
  line-height: 1.25;
}
.table-sort__icon {
  align-items: center;
  color: var(--color-muted);
  display: inline-flex;
  flex: none;
  height: 1rem;
  width: 1rem;
}
.table-sort__icon svg {
  height: 1rem;
  width: 1rem;
}
.table-sortable--active .table-sort__label {
  color: var(--color-navy);
}
.table-sortable--active .table-sort__icon {
  color: var(--color-primary);
}

/* Shared AJAX pagination (static/js/common/ajax-pagination.js): the replaceable result area of a paginated screen. While another page
   is loading it dims slightly and ignores clicks, but keeps its size, so nothing jumps and the current records stay visible. */
[data-ajax-results] {
  transition: opacity 0.15s ease;
}
[data-ajax-results].is-loading {
  opacity: 0.55;
  pointer-events: none;
}
[data-ajax-results]:focus {
  outline: none;
}

/* Filter Clear button (Front Desk tabs, Reservations, Guests): used as `button button-outline-primary filter-clear-button` with a leading
   eraser icon, so every list shows the same compact [icon] Clear action. Size, padding, radius, border and font come from .button;
   a screen's own class only places it in that screen's filter grid. */
.filter-clear-button {
  gap: var(--space-2);
  white-space: nowrap;
}
.filter-clear-button svg {
  height: var(--icon-size-action);
  width: var(--icon-size-action);
}
@media (max-width: 40rem) {
  /* Mobile: Clear is a compact action at the right under the last filter, not a full-width bar. */
  .filter-clear-button {
    min-width: 5.5rem;
  }
}

/* Header action pair (Cancel + Save on the Guest form and Create Reservation). Desktop/tablet keep each screen's own layout; on mobile the
   header stacks and the pair drops under the description as a compact, right-aligned group: both buttons share one fixed width
   (--header-action-width, default 7.5rem, used as a maximum; never stretched to the row) with a 0.75rem gap, as two equal grid
   columns, so on very narrow screens they stay equal and shrink together instead of overflowing. A Cancel that lives in its own <form> is sized by that form. */
@media (max-width: 40rem) {
  .page-header.page-header--actions {
    flex-direction: column;
  }
  .page-header .header-action-pair {
    align-items: stretch;
    display: grid;
    gap: var(--space-3);
    grid-template-columns: repeat(2, minmax(0, var(--header-action-width, 7.5rem)));
    justify-content: end;
    width: 100%;
  }
  .page-header .header-action-pair > .button,
  .page-header .header-action-pair > form {
    min-width: 0;
    width: 100%;
  }
  .page-header .header-action-pair > form {
    display: flex;
  }
  .page-header .header-action-pair > form > .button {
    flex: 1;
    min-width: 0;
    width: 100%;
  }
  .page-header .header-action-pair .button {
    white-space: nowrap;
  }
}
@media (max-width: 24rem) {
  /* 320px: trim the horizontal padding so the longest label still fits inside the shrunken, equal-width buttons. */
  .page-header .header-action-pair .button {
    padding-inline: var(--space-2);
  }
}

/* Required-field marker: only the asterisk after a label is red (the shared danger colour); the label text keeps its own colour. */
.required-marker {
  color: var(--color-danger);
}

/* Searchable select (static/js/common/searchable-select.js): a text input that filters a listbox of server-supplied options. The
   input keeps the shared form-control look, the list reuses the dropdown tokens. */
.searchable-select {
  position: relative;
  width: 100%;
}
.searchable-select__input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2352606d' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-position: right var(--space-3) center;
  background-repeat: no-repeat;
  background-size: 1rem;
  padding-right: 2.25rem;
  text-overflow: ellipsis;
}
.searchable-select__list {
  background: var(--color-dropdown-surface);
  border: 1px solid var(--color-dropdown-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-dropdown);
  left: 0;
  list-style: none;
  margin: var(--dropdown-gap) 0 0;
  max-height: 15rem;
  overflow-x: hidden;
  overflow-y: auto;
  padding: var(--space-1);
  position: absolute;
  right: 0;
  z-index: var(--z-dropdown);
}
/* While open the list is a floating overlay attached to <body> (searchable-select.js sets left, top, width and max-height from the input's
   position), so no parent card can clip it or grow because of it. */
.searchable-select__list--floating {
  margin: 0;
  position: fixed;
  right: auto;
}
.searchable-select__list[hidden] {
  display: none;
}
.searchable-select__option {
  border-radius: var(--radius-sm);
  overflow-wrap: anywhere;
  color: var(--color-dropdown-text);
  cursor: pointer;
  padding: var(--space-2) var(--space-3);
}
.searchable-select__option.is-active,
.searchable-select__option:hover {
  background: var(--color-dropdown-hover);
}
.searchable-select__option[aria-selected="true"] {
  background: var(--color-dropdown-selected);
  color: var(--color-dropdown-selected-text);
  font-weight: 700;
}
.searchable-select__message {
  color: var(--color-dropdown-disabled-text);
  padding: var(--space-2) var(--space-3);
}
.searchable-select__status {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}
