/* ============================================================
   BookEngine control states — the states every interactive element
   needs, defined once.

   Loaded after tokens.css and before the page stylesheets. Scoped to the
   redesigned page roots so legacy screens are untouched.

   Nothing here changes how the product looks to a mouse user:
   :focus-visible only matches keyboard focus, and the disabled and busy
   rules only apply to elements already in those states.

   Audited 2026-08-25: the nine page stylesheets carried 86 :hover rules,
   31 :focus and 5 :focus-visible — so most controls had a hover state
   designed and no keyboard state at all.
   ============================================================ */

.pd, .mp, .rs, .cm, .lb, .photos-page {

  /* one ring, learned once. Outline rather than box-shadow so it never
     fights a component's own shadow, and follows border-radius. */
  --ring:        2px solid var(--blue);
  --ring-offset: 2px;
}

/* ---------- keyboard focus ----------
   :focus-visible, not :focus — a mouse click should not draw a ring, which
   is the reason people delete focus styles altogether and strand keyboard
   users. */

.pd :focus-visible,
.mp :focus-visible,
.rs :focus-visible,
.cm :focus-visible,
.lb :focus-visible,
.photos-page :focus-visible {
  outline: var(--ring);
  outline-offset: var(--ring-offset);
}

/* On the navy bar a blue ring disappears into the ground. */
.lb-bar :focus-visible,
.lb-nav-user :focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 2px;
}

/* Rows and menu items are large targets; the ring sits inside so it is not
   clipped by the container that scrolls them. */
.lb-row:focus-visible,
.rs-opt:focus-visible,
.lb-nav-item:focus-visible {
  outline: var(--ring);
  outline-offset: -2px;
}

/* ---------- disabled ----------
   Consistent, and never conveyed by colour alone: the cursor changes too. */

.pd :disabled,
.mp :disabled,
.rs :disabled,
.cm :disabled,
.lb :disabled,
.photos-page :disabled,
.pd [disabled],
.mp [disabled],
.rs [disabled],
.cm [disabled],
.lb [disabled],
.photos-page [disabled] {
  cursor: not-allowed;
}

/* A disabled control that still has to be *read* — a submitted status, a
   locked rate — keeps full contrast. Dimming it to 40% makes the value
   unreadable, which is a different thing from unavailable. */
.lb select[disabled],
.rs select[disabled],
.cm select[disabled] { opacity: 1; }

/* ---------- pressed ----------
   A press should register even when the network is slow. */

.pd button:active:not(:disabled),
.mp button:active:not(:disabled),
.rs button:active:not(:disabled),
.cm button:active:not(:disabled),
.lb button:active:not(:disabled),
.photos-page button:active:not(:disabled) { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
  .pd button:active, .mp button:active, .rs button:active,
  .cm button:active, .lb button:active, .photos-page button:active { transform: none; }
}

/* ---------- busy ----------
   For actions that take long enough to need saying so. Add .is-busy to the
   button; the label stays put so the button does not resize and shift the
   layout around it. */

.pd .is-busy,
.mp .is-busy,
.rs .is-busy,
.cm .is-busy,
.lb .is-busy,
.photos-page .is-busy {
  position: relative;
  pointer-events: none;
}

/* Hide the label by hiding its children rather than setting a transparent
   colour: colour loses to any component rule that sets its own, and it does
   nothing for a button whose label is an icon. visibility keeps the button's
   measured size, so nothing around it shifts. */
.pd .is-busy > *,
.mp .is-busy > *,
.rs .is-busy > *,
.cm .is-busy > *,
.lb .is-busy > *,
.photos-page .is-busy > * { visibility: hidden; }

.pd .is-busy::after,
.mp .is-busy::after,
.rs .is-busy::after,
.cm .is-busy::after,
.lb .is-busy::after,
.photos-page .is-busy::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  color: #ffffff;
  animation: bng-spin .6s linear infinite;
}

/* a busy button on a light ground needs a dark spinner */
.pd .btn-default.is-busy::after,
.cm .btn-default.is-busy::after,
.lb .rs-btn.is-busy::after,
.lb .lb-btn.is-busy::after,
.lb .lb-btn-ghost.is-busy::after { color: var(--navy); }

@keyframes bng-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .pd .is-busy::after, .mp .is-busy::after, .rs .is-busy::after,
  .cm .is-busy::after, .lb .is-busy::after, .photos-page .is-busy::after {
    animation: none;
    border-top-color: currentColor;
    opacity: .5;
  }
}

/* ---------- skip link ----------
   Keyboard users should not have to tab through the whole nav to reach the
   table they came for. Invisible until focused. */

.bng-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 10px 16px;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 600;
  color: var(--navy);
  background: #ffffff;
  border: 2px solid var(--blue);
  border-radius: 0 0 var(--r) 0;
  text-decoration: none;
}

.bng-skip:focus { left: 0; }
