/* ==========================================================================
   Calypso Residence — base component set
   Button · Input · Card · Badge · Table · Modal · Slide-over · Skeleton ·
   Toast · Stat card · Empty state · Pagination · Tabs · Loading bar
   Layer 3 of the token architecture: each component declares its own tokens,
   which default to semantic ones. Variants re-point the component token, so a
   variant never restates a raw colour.
   ========================================================================== */

/* ==========================================================================
   BUTTON
   ========================================================================== */
.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text-primary);
  --btn-border: transparent;
  --btn-shadow: none;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  min-height: 44px;                 /* touch target floor */
  border-radius: var(--radius-pill);
  border: 1px solid var(--btn-border);
  background: var(--btn-bg);
  color: var(--btn-fg);
  box-shadow: var(--btn-shadow);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition:
    background-color var(--dur-fast) var(--ease-state),
    color var(--dur-fast) var(--ease-state),
    border-color var(--dur-fast) var(--ease-state),
    box-shadow var(--dur-fast) var(--ease-state),
    transform var(--dur-fast) var(--ease-state);
}

.btn:hover  { transform: translateY(-1px); }
.btn:active { transform: translateY(0); transition-duration: var(--dur-instant); }

.btn[disabled],
.btn[aria-disabled='true'],
.btn.is-loading {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  pointer-events: none;
}

/* Primary — gold fill, dark ink. 8.9:1, comfortably AA. */
.btn--primary {
  --btn-bg: var(--gold);
  --btn-fg: var(--text-on-gold);
  --btn-shadow: var(--shadow-gold);
  font-weight: var(--weight-semibold);
}
.btn--primary:hover { --btn-bg: var(--gold-dark); --btn-fg: #fff; }

/* The gold sheen that sweeps across primary buttons on hover (§9). */
.btn--primary::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    115deg,
    transparent 30%,
    rgba(255, 255, 255, 0.38) 50%,
    transparent 70%
  );
  transform: translateX(-120%);
  transition: transform var(--dur-slow) var(--ease-state);
}
.btn--primary:hover::after { transform: translateX(120%); }
@media (prefers-reduced-motion: reduce) {
  .btn--primary::after { display: none; }
}

/* Dark — Template B's rounded charcoal CTA. */
.btn--dark {
  --btn-bg: var(--bg-deep);
  --btn-fg: var(--text-on-dark);
}
.btn--dark:hover { --btn-bg: var(--bg-deep-alt); box-shadow: var(--shadow-lift); }

/* Outline — gold hairline, gold-ink label (AA on cream). */
.btn--outline {
  --btn-border: var(--gold-dark);
  --btn-fg: var(--gold-ink);
}
.btn--outline:hover { --btn-bg: var(--gold-wash); --btn-border: var(--gold); }

.on-dark .btn--outline,
.band--deep .btn--outline {
  --btn-border: var(--gold-soft);
  --btn-fg: var(--gold-soft);
}
.on-dark .btn--outline:hover { --btn-bg: rgba(224, 200, 146, 0.12); }

/* Ghost / quiet */
.btn--ghost { --btn-fg: var(--text-muted); }
.btn--ghost:hover { --btn-bg: var(--gold-wash); --btn-fg: var(--gold-ink); }

.btn--subtle {
  --btn-bg: var(--bg-sunken);
  --btn-fg: var(--text-secondary);
  --btn-border: var(--line);
}
.btn--subtle:hover { --btn-bg: var(--bg-sand); --btn-fg: var(--text-primary); }

/* Destructive — always paired with a confirmation dialog. */
.btn--danger { --btn-bg: var(--danger); --btn-fg: #fff; }
.btn--danger:hover { --btn-bg: var(--danger-ink); }

.btn--danger-outline { --btn-border: var(--danger); --btn-fg: var(--danger-ink); }
.btn--danger-outline:hover { --btn-bg: var(--danger-wash); }

/* Sizes */
.btn--sm { padding: var(--space-2) var(--space-4); min-height: 36px; font-size: var(--text-sm); }
.btn--xs { padding: var(--space-1) var(--space-3); min-height: 30px; font-size: var(--text-xs); gap: var(--space-1); }
.btn--lg { padding: var(--space-4) var(--space-8); min-height: 54px; font-size: var(--text-md); }
.btn--block { display: flex; width: 100%; }

/* Icon-only. ALWAYS needs aria-label — see the a11y note in the README. */
.btn--icon {
  padding: 0;
  width: 44px;
  min-height: 44px;
  border-radius: var(--radius-pill);
  flex: 0 0 auto;
}
.btn--icon.btn--sm { width: 36px; min-height: 36px; }
.btn--icon.btn--xs { width: 30px; min-height: 30px; }

.btn .icon { width: 1.15em; height: 1.15em; flex: 0 0 auto; }

/* Loading state — spinner replaces the label, width does not jump. */
.btn.is-loading .btn__label { visibility: hidden; }
.btn.is-loading::before {
  content: '';
  position: absolute;
  width: 1em; height: 1em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 600ms linear infinite;
}

/* POS keypad and other big tap targets. */
.btn--tap {
  min-height: 64px;
  border-radius: var(--radius-md);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
}

/* ==========================================================================
   CHIP — quick actions and filter pills
   ========================================================================== */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  min-height: 38px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--bg-elevated);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
  cursor: pointer;
  transition:
    border-color var(--dur-fast) var(--ease-state),
    background-color var(--dur-fast) var(--ease-state),
    color var(--dur-fast) var(--ease-state),
    box-shadow var(--dur-fast) var(--ease-state),
    transform var(--dur-fast) var(--ease-state);
}
.chip:hover {
  border-color: var(--gold);
  color: var(--gold-ink);
  transform: translateY(var(--lift-item));
  box-shadow: var(--shadow-soft), 0 0 0 4px var(--gold-wash);
}
.chip[aria-pressed='true'],
.chip.is-active {
  background: var(--gold-wash-strong);
  border-color: var(--gold);
  color: var(--gold-ink);
}
.chip .icon { width: 16px; height: 16px; }
.chip__count {
  font-size: var(--text-2xs);
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   FORM CONTROLS
   ========================================================================== */
.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field + .field { margin-top: var(--space-5); }

.label {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.label__required { color: var(--danger-ink); }
.label__optional { color: var(--text-faint); font-weight: var(--weight-regular); font-size: var(--text-xs); }

.input,
.select,
.textarea {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  min-height: 46px;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--text-base);
  transition:
    border-color var(--dur-fast) var(--ease-state),
    box-shadow var(--dur-fast) var(--ease-state),
    background-color var(--dur-fast) var(--ease-state);
}
.textarea { min-height: 120px; resize: vertical; line-height: var(--leading-normal); }

.input::placeholder, .textarea::placeholder {
  color: var(--text-faint);
  opacity: 1;                        /* Firefox dims placeholders by default */
}

.input:hover, .select:hover, .textarea:hover { border-color: var(--line-strong); }

.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px var(--gold-wash);
  outline: none;
}

.input[disabled], .select[disabled], .textarea[disabled] {
  background: var(--bg-sunken);
  color: var(--text-faint);
  cursor: not-allowed;
}
.input[readonly] { background: var(--bg-sunken); }

/* Invalid — colour is never the only signal; the message below carries it. */
.input[aria-invalid='true'],
.select[aria-invalid='true'],
.textarea[aria-invalid='true'] {
  border-color: var(--danger);
  background: var(--danger-wash);
}
.input[aria-invalid='true']:focus-visible {
  box-shadow: 0 0 0 3px rgba(176, 74, 63, 0.18);
}

.select {
  appearance: none;
  padding-right: var(--space-10);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%236B6259' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
}

.field__hint  { font-size: var(--text-xs); color: var(--text-muted); }
.field__error {
  font-size: var(--text-xs);
  color: var(--danger-ink);
  font-weight: var(--weight-medium);
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
}
.field__error .icon { width: 14px; height: 14px; flex: 0 0 auto; margin-top: 1px; }

/* Input with a leading symbol — the ₦ prefix on money fields. */
.input-group { position: relative; display: flex; align-items: center; }
.input-group__prefix {
  position: absolute;
  left: var(--space-4);
  color: var(--text-muted);
  font-size: var(--text-base);
  pointer-events: none;
}
.input-group__prefix + .input { padding-left: var(--space-8); }

/* Checkbox + radio */
.check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  cursor: pointer;
  font-size: var(--text-base);
  padding: var(--space-1) 0;
}
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check__box {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  margin-top: 1px;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius-xs);
  background: var(--bg-elevated);
  display: grid;
  place-items: center;
  transition: all var(--dur-fast) var(--ease-state);
}
.check input[type='radio'] + .check__box { border-radius: 50%; }
.check__box::after {
  content: '';
  width: 10px; height: 10px;
  transform: scale(0);
  transition: transform var(--dur-fast) var(--ease-entrance);
  background: var(--text-on-gold);
  clip-path: polygon(14% 44%, 0 65%, 42% 100%, 100% 16%, 82% 0%, 38% 62%);
}
.check input[type='radio'] + .check__box::after {
  clip-path: none;
  border-radius: 50%;
  width: 8px; height: 8px;
}
.check input:checked + .check__box { background: var(--gold); border-color: var(--gold); }
.check input:checked + .check__box::after { transform: scale(1); }
.check input:focus-visible + .check__box { box-shadow: var(--focus-ring); }
.check input[disabled] + .check__box { background: var(--bg-sunken); border-color: var(--line); }

/* Switch */
.switch { display: inline-flex; align-items: center; gap: var(--space-3); cursor: pointer; }
.switch input { position: absolute; opacity: 0; }
.switch__track {
  width: 44px; height: 26px;
  border-radius: var(--radius-pill);
  background: var(--line-strong);
  padding: 3px;
  transition: background-color var(--dur-fast) var(--ease-state);
}
.switch__thumb {
  width: 20px; height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(26,22,20,.3);
  transition: transform var(--dur-fast) var(--ease-state);
}
.switch input:checked + .switch__track { background: var(--gold); }
.switch input:checked + .switch__track .switch__thumb { transform: translateX(18px); }
.switch input:focus-visible + .switch__track { box-shadow: var(--focus-ring); }

/* Quantity stepper — POS cart, guest counts. */
.stepper {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--bg-elevated);
  overflow: hidden;
}
.stepper__btn {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  color: var(--text-secondary);
  transition: background-color var(--dur-fast) var(--ease-state);
}
.stepper__btn:hover:not([disabled]) { background: var(--gold-wash); color: var(--gold-ink); }
.stepper__btn[disabled] { opacity: 0.35; cursor: not-allowed; }
.stepper__value {
  min-width: 40px;
  text-align: center;
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  border: 0;
  background: transparent;
  padding: 0;
}

/* ==========================================================================
   CARD
   ========================================================================== */
.card {
  --card-bg: var(--bg-elevated);
  --card-radius: var(--radius-lg);
  background: var(--card-bg);
  border-radius: var(--card-radius);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  position: relative;
  transition:
    transform var(--dur-base) var(--ease-entrance),
    box-shadow var(--dur-base) var(--ease-entrance),
    border-color var(--dur-base) var(--ease-state);
}

/* Lift 6px, deepen the shadow, zoom the image inside its mask (§9). */
.card--interactive:hover {
  transform: translateY(var(--lift-card));
  box-shadow: var(--shadow-lift);
  border-color: var(--gold-soft);
}
.card--interactive:focus-within {
  border-color: var(--gold);
  box-shadow: var(--shadow-lift);
}

.card__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--media-ratio, 4 / 3);
  background: var(--bg-sunken);
}
.card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slower) var(--ease-entrance);
}
.card--interactive:hover .card__media img { transform: scale(var(--zoom-image)); }

.card__body { padding: var(--space-6); }
.card__body--tight { padding: var(--space-4); }
.card__header {
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.card__title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-snug);
  margin: 0;
}
.card__title--sm { font-size: var(--text-lg); }
.card__meta { font-size: var(--text-sm); color: var(--text-muted); }
.card__footer {
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--line);
  background: var(--bg-sunken);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* Whole-card link without nesting interactive elements. */
.card__link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}
.card__body .btn,
.card__footer .btn { position: relative; z-index: 2; }

/* Price badge in the media corner (Template A's rooms carousel). */
.card__price-badge {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  z-index: 2;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  background: var(--glass-dark);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  color: var(--text-on-dark);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  border: 1px solid rgba(224, 200, 146, 0.28);
  white-space: nowrap;
}
.card__price-badge small {
  font-weight: var(--weight-regular);
  opacity: 0.75;
  font-size: var(--text-xs);
}

/* Panel — the console's card. Squarer, denser. */
.panel {
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}
.panel__header {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}
.panel__title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  margin: 0;
}
.panel__body { padding: var(--space-5); }
.panel__body--flush { padding: 0; }
.panel__footer {
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--line);
  background: var(--bg-sunken);
}

/* Glass panel — floating booking bar, display overlays. */
.glass {
  background: var(--glass-light);
  backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.55);
  box-shadow: var(--shadow-lift), var(--shadow-inset);
  border-radius: var(--radius-lg);
}
.glass--dark {
  background: var(--glass-dark);
  border-color: rgba(224, 200, 146, 0.18);
  color: var(--text-on-dark);
}
/* Fallback where backdrop-filter is unsupported — opaque, still legible. */
@supports not (backdrop-filter: blur(1px)) {
  .glass { background: rgba(255, 255, 255, 0.96); }
  .glass--dark { background: rgba(20, 17, 15, 0.94); }
}

/* ==========================================================================
   BADGE
   ========================================================================== */
.badge {
  --badge-bg: var(--bg-sunken);
  --badge-fg: var(--text-secondary);
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 3px var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--badge-bg);
  color: var(--badge-fg);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  line-height: 1.5;
  white-space: nowrap;
}
.badge--gold    { --badge-bg: var(--gold-wash-strong); --badge-fg: var(--gold-ink); }
.badge--success { --badge-bg: var(--success-wash); --badge-fg: var(--success-ink); }
.badge--warning { --badge-bg: var(--warning-wash); --badge-fg: var(--warning-ink); }
.badge--danger  { --badge-bg: var(--danger-wash);  --badge-fg: var(--danger-ink); }
.badge--info    { --badge-bg: var(--info-wash);    --badge-fg: var(--info-ink); }
.badge--solid   { --badge-bg: var(--gold); --badge-fg: var(--text-on-gold); }

/* A dot carries the same meaning as the colour for anyone who cannot see it —
   the text label beside it is always present. */
.badge__dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}

/* Notification count on the console header. */
.badge--count {
  min-width: 18px; height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--danger);
  color: #fff;
  font-size: var(--text-2xs);
  display: inline-grid;
  place-items: center;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   TABLE
   ========================================================================== */
.table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-md);
}

.table { width: 100%; font-size: var(--text-base); }

.table th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--line);
  background: var(--bg-sunken);
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 1;
}
.table td {
  padding: var(--space-4);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.table tbody tr { transition: background-color var(--dur-fast) var(--ease-state); }
.table tbody tr:hover { background: var(--row-hover, var(--gold-wash)); }
.table tbody tr:last-child td { border-bottom: 0; }

.table--striped tbody tr:nth-child(even) { background: var(--row-stripe, rgba(26,22,20,.018)); }
.table--compact th, .table--compact td { padding: var(--space-2) var(--space-3); }

.table td.is-numeric, .table th.is-numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Sortable header — a real <button> so it is keyboard reachable. */
.table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}
.table__sort:hover { color: var(--gold-ink); }
.table__sort .icon { width: 12px; height: 12px; opacity: 0.4; transition: opacity var(--dur-fast); }
.table__sort[aria-sort='ascending'] .icon,
.table__sort[aria-sort='descending'] .icon { opacity: 1; color: var(--gold-ink); }
.table__sort[aria-sort='descending'] .icon { transform: rotate(180deg); }

/* Below 640px, tables become stacked definition rows. Each cell needs
   data-label="Column name" for the label to appear. */
@media (max-width: 640px) {
  .table--stack thead { display: none; }
  .table--stack tbody tr {
    display: block;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-3);
    padding: var(--space-2);
    background: var(--bg-elevated);
  }
  .table--stack td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--line);
    text-align: right;
  }
  .table--stack td:last-child { border-bottom: 0; }
  .table--stack td::before {
    content: attr(data-label);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--text-muted);
    text-align: left;
    flex: 0 0 auto;
  }
}

/* ==========================================================================
   MODAL — scale-fade from 0.96, backdrop blurs in (§9)
   Built on <dialog> so focus trapping and Esc are the platform's job.
   ========================================================================== */
.modal {
  padding: 0;
  border: 0;
  background: transparent;
  max-width: min(560px, calc(100vw - 2 * var(--space-6)));
  width: 100%;
  max-height: calc(100vh - 2 * var(--space-8));
  overflow: visible;
  color: var(--text-primary);
}
.modal::backdrop {
  background: rgba(20, 17, 15, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  animation: fade-in var(--dur-quick) var(--ease-state) both;
}
.modal[open] {
  /* End state declared outright — see the note on .slideover[open] below.
     Without it, a frozen or skipped animation leaves the dialog on its FROM
     frame: scaled down and fully transparent. */
  opacity: 1;
  transform: none;
  /* NO fill-mode. An animation with `both` outranks the element's own
     declarations — the two lines above would be ignored and the dialog would
     be held on its first frame. With no fill, the animation only affects the
     element while it is actually running; before and after, these apply. */
  animation: scale-fade-in var(--dur-base) var(--ease-entrance);
}
.modal__inner {
  background: var(--bg-elevated);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 2 * var(--space-8));
}
.modal__header {
  padding: var(--space-6) var(--space-6) var(--space-4);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
}
.modal__title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  margin: 0;
}
.modal__body {
  padding: 0 var(--space-6) var(--space-6);
  overflow-y: auto;
  flex: 1;
}
.modal__footer {
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--line);
  background: var(--bg-sunken);
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.modal--wide { max-width: min(920px, calc(100vw - 2 * var(--space-6))); }

@media (max-width: 640px) {
  .modal {
    max-width: 100vw;
    width: 100vw;
    margin: 0;
    position: fixed;
    bottom: 0; left: 0;
    max-height: 88vh;
  }
  .modal__inner { border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
}

/* ==========================================================================
   SLIDE-OVER — room detail panel on the status board
   ========================================================================== */
.slideover {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(460px, 100vw);
  max-width: 100vw;
  height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  max-height: none;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-pop);
  color: var(--text-primary);
  display: flex;
  flex-direction: column;
}
.slideover::backdrop {
  background: rgba(20, 17, 15, 0.45);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  animation: fade-in var(--dur-quick) var(--ease-state) both;
}
/* The panel's resting position is declared HERE, not left to the animation.
   ---------------------------------------------------------------------------
   `animation-fill-mode: both` holds an element on its FIRST frame until the
   animation actually runs. The first frame of slide-in-right is
   translateX(100%) — the panel parked off the right edge of the screen.

   So in any situation where the animation does not run — a tab that was in
   the background when the panel opened, a device throttling animations, a
   browser that skipped it — the panel opened, loaded its content, and sat
   entirely outside the viewport with only a sliver of shadow visible. It
   looked like the panel had failed to load. It had loaded perfectly and was
   parked off-screen.

   Declaring transform:none means the worst case is a panel that appears
   without sliding, rather than one that cannot be seen at all. */
.slideover[open] {
  transform: none;
  animation: slide-in-right var(--dur-base) var(--ease-entrance);
}

.slideover__header {
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex: 0 0 auto;
}
.slideover__body { padding: var(--space-6); overflow-y: auto; flex: 1; }
.slideover__footer {
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--line);
  background: var(--bg-sunken);
  display: flex;
  gap: var(--space-3);
  flex: 0 0 auto;
}
@media (max-width: 520px) {
  .slideover { width: 100vw; }
}

/* ==========================================================================
   SKELETON — shimmer, never a bare spinner or a blank screen
   ========================================================================== */
.skeleton {
  background: linear-gradient(
    90deg,
    var(--bg-sunken) 25%,
    rgba(255, 255, 255, 0.75) 50%,
    var(--bg-sunken) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.6s var(--ease-state) infinite;
  border-radius: var(--radius-xs);
  color: transparent;
  user-select: none;
  pointer-events: none;
}
.skeleton--text   { height: 0.85em; margin-block: 0.2em; border-radius: var(--radius-pill); }
.skeleton--title  { height: 1.5em; width: 55%; border-radius: var(--radius-pill); }
.skeleton--line   { height: 0.85em; width: 100%; border-radius: var(--radius-pill); }
.skeleton--line-short { width: 62%; }
.skeleton--media  { aspect-ratio: 4 / 3; width: 100%; border-radius: 0; }
.skeleton--avatar { width: 44px; height: 44px; border-radius: 50%; }
.skeleton--chip   { height: 38px; width: 110px; border-radius: var(--radius-pill); }
.skeleton--tile   { aspect-ratio: 1; border-radius: var(--radius-sm); }

@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; background: var(--bg-sunken); }
}

/* ==========================================================================
   TOAST
   ========================================================================== */
.toast-stack {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: min(400px, calc(100vw - 2 * var(--space-4)));
  pointer-events: none;
}
@media (max-width: 640px) {
  .toast-stack { bottom: var(--space-4); right: var(--space-4); left: var(--space-4); width: auto; }
}

.toast {
  --toast-accent: var(--gold);
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-left: 3px solid var(--toast-accent);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lift);
  animation: toast-in var(--dur-base) var(--ease-entrance) both;
}
.toast--success { --toast-accent: var(--success); }
.toast--error   { --toast-accent: var(--danger); }
.toast--warning { --toast-accent: var(--warning); }
.toast--info    { --toast-accent: var(--info); }

.toast.is-leaving { animation: toast-out var(--dur-quick) var(--ease-exit) both; }

.toast__icon { flex: 0 0 auto; width: 20px; height: 20px; color: var(--toast-accent); margin-top: 1px; }
.toast__content { flex: 1; min-width: 0; }
.toast__title { font-weight: var(--weight-semibold); font-size: var(--text-base); }
.toast__message { font-size: var(--text-sm); color: var(--text-muted); }
.toast__close { flex: 0 0 auto; color: var(--text-faint); padding: 2px; border-radius: var(--radius-xs); }
.toast__close:hover { color: var(--text-primary); }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
@keyframes toast-out {
  to { opacity: 0; transform: translateX(24px); }
}

/* ==========================================================================
   STAT CARD — dashboards. Number counts up from zero on first paint (§9).
   ========================================================================== */
.stat {
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  position: relative;
  overflow: hidden;
  min-width: 0;
}
.stat__label {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.stat__value {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-semibold);
  line-height: 1.05;
  letter-spacing: var(--tracking-display);
  font-variant-numeric: tabular-nums;
  word-break: break-word;
}
.stat__foot { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

/* Delta. The arrow glyph plus the sign means colour is not the only cue. */
.stat__delta {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}
.stat__delta--up   { color: var(--success-ink); }
.stat__delta--down { color: var(--danger-ink); }
.stat__delta--flat { color: var(--text-faint); }
.stat__delta .icon { width: 12px; height: 12px; }

.stat__caption { font-size: var(--text-xs); color: var(--text-faint); }

.stat__spark {
  height: 34px;
  margin-top: var(--space-1);
  width: 100%;
}
.stat__accent {
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--stat-accent, var(--gold));
}

/* ==========================================================================
   EMPTY STATE
   Matters more than usual here: the production seed ships zero rooms, so these
   are the first screens Victoria's team will ever see.
   ========================================================================== */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-4);
  padding: clamp(var(--space-10), 8vw, var(--space-20)) var(--space-6);
  max-width: 480px;
  margin-inline: auto;
}
.empty__icon {
  width: 72px; height: 72px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--gold-wash);
  color: var(--gold-ink);
  box-shadow: 0 0 0 8px rgba(193, 151, 75, 0.05);
}
.empty__icon .icon { width: 32px; height: 32px; }
.empty__title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  margin: 0;
}
.empty__text { color: var(--text-muted); font-size: var(--text-base); text-wrap: pretty; }
.empty__actions { display: flex; gap: var(--space-3); flex-wrap: wrap; justify-content: center; }

/* Empty state sitting inside a table body. */
td .empty { padding-block: var(--space-12); }

/* ==========================================================================
   PAGINATION
   ========================================================================== */
.pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  flex-wrap: wrap;
}
.pagination__summary { font-size: var(--text-sm); color: var(--text-muted); }
.pagination__list { display: flex; align-items: center; gap: var(--space-1); }
.pagination__link {
  min-width: 38px; height: 38px;
  padding: 0 var(--space-3);
  display: inline-grid;
  place-items: center;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  transition: background-color var(--dur-fast) var(--ease-state), color var(--dur-fast) var(--ease-state);
}
.pagination__link:hover { background: var(--gold-wash); color: var(--gold-ink); }
.pagination__link[aria-current='page'] {
  background: var(--gold);
  color: var(--text-on-gold);
  font-weight: var(--weight-semibold);
}
.pagination__link[aria-disabled='true'] { opacity: 0.35; pointer-events: none; }
.pagination__gap { padding: 0 var(--space-2); color: var(--text-faint); }

/* ==========================================================================
   TABS
   ========================================================================== */
.tabs {
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  padding: var(--space-3) var(--space-5);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-state), border-color var(--dur-fast) var(--ease-state);
}
.tab:hover { color: var(--text-primary); }
.tab[aria-selected='true'] {
  color: var(--gold-ink);
  border-bottom-color: var(--gold);
  font-weight: var(--weight-semibold);
}

/* ==========================================================================
   LOADING BAR — thin gold bar on navigation and form submit (§9)
   The single most important cue that a full-page-load PHP app is not frozen.
   ========================================================================== */
.loading-bar {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 100%;
  z-index: var(--z-loadingbar);
  background: transparent;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-state);
}
.loading-bar.is-active { opacity: 1; }
.loading-bar__fill {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--gold-dark), var(--gold), var(--gold-soft));
  box-shadow: 0 0 10px rgba(193, 151, 75, 0.7);
  transition: width var(--dur-base) var(--ease-state);
}

/* ==========================================================================
   MISC SHARED PIECES
   ========================================================================== */

/* Star rating. The numeric value beside it is the accessible source of truth. */
.stars { display: inline-flex; align-items: center; gap: 1px; color: var(--gold); }
.stars .icon { width: 14px; height: 14px; }
.stars__empty { color: var(--line-strong); }

/* Divider with centred label. */
.divider {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  color: var(--text-faint);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.divider::before, .divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}

/* Copy-to-clipboard row — bank account numbers at checkout. */
.copy-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.copy-row__value {
  font-family: var(--font-mono);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
  word-break: break-all;
}

/* Tooltip via data-tooltip. Decorative only — never the sole carrier of info. */
[data-tooltip] { position: relative; }
[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  padding: var(--space-2) var(--space-3);
  background: var(--bg-deep);
  color: var(--text-on-dark);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  border-radius: var(--radius-xs);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-state), transform var(--dur-fast) var(--ease-state);
  z-index: var(--z-dropdown);
}
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Avatar */
.avatar {
  width: var(--avatar-size, 40px);
  height: var(--avatar-size, 40px);
  border-radius: 50%;
  object-fit: cover;
  background: var(--gold-wash);
  color: var(--gold-ink);
  display: inline-grid;
  place-items: center;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  flex: 0 0 auto;
  text-transform: uppercase;
}
.avatar--sm { --avatar-size: 30px; font-size: var(--text-xs); }
.avatar--lg { --avatar-size: 56px; font-size: var(--text-md); }

/* Icon sizing default for the sprite. */
.icon {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon--sm { width: 16px; height: 16px; }
.icon--lg { width: 28px; height: 28px; }
.icon--filled { fill: currentColor; stroke: none; }
