/* ==========================================================================
   Motion
   --------------------------------------------------------------------------
   Every effect here is opt-in twice: the `.js` class means the script that
   drives it is running, and `prefers-reduced-motion` removes it entirely. A
   reveal that hides content and then never un-hides it is the worst possible
   failure, so nothing is hidden unless JavaScript has already confirmed it can
   put it back.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Reveal on scroll
   -------------------------------------------------------------------------- */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 620ms var(--ease) var(--reveal-delay, 0ms),
    transform 620ms var(--ease) var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* --------------------------------------------------------------------------
   Staggered entry — used when live panel data arrives
   -------------------------------------------------------------------------- */
.enter {
  animation: enter 460ms var(--ease) both;
  animation-delay: var(--enter-delay, 0ms);
}
@keyframes enter {
  from { opacity: 0; transform: translateY(8px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   X-ray cursor
   --------------------------------------------------------------------------
   backdrop-filter reads the pixels already painted underneath, so one element
   inverts text, photographs and video alike without duplicating any of them.
   -------------------------------------------------------------------------- */
.xray {
  position: fixed;
  top: 0; left: 0;
  width: 176px; height: 176px;
  margin: -88px 0 0 -88px;
  border-radius: 50%;
  z-index: 140;
  pointer-events: none;
  transform: translate3d(var(--x, 50vw), var(--y, 50vh), 0) scale(.4);
  opacity: 0;
  transition: opacity 200ms var(--ease), transform 200ms var(--ease);
  -webkit-backdrop-filter: invert(1) contrast(1.08) saturate(.15);
          backdrop-filter: invert(1) contrast(1.08) saturate(.15);
  /* The scale sits on the same transform as the position, so it has to be
     re-declared rather than added — hence the duplicated translate below. */
}
.xray.is-on {
  opacity: 1;
  transform: translate3d(var(--x, 50vw), var(--y, 50vh), 0) scale(1);
}

.xray__ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(225, 29, 46, .55);
  box-shadow: inset 0 0 26px rgba(225, 29, 46, .16);
}
.xray__cross::before,
.xray__cross::after {
  content: '';
  position: absolute;
  background: rgba(225, 29, 46, .38);
}
.xray__cross::before { left: 50%; top: 42%; width: 1px; height: 16%; }
.xray__cross::after  { top: 50%; left: 42%; height: 1px; width: 16%; }

/* --------------------------------------------------------------------------
   Route transition — a detector pass over the page
   -------------------------------------------------------------------------- */
.scan-wipe {
  position: fixed;
  inset: 0;
  z-index: 130;
  pointer-events: none;
  opacity: 0;
  overflow: hidden;
}
.scan-wipe.is-running { opacity: 1; }

.scan-wipe__band,
.scan-wipe__line,
.scan-wipe__grid,
.scan-wipe__label {
  position: absolute;
  left: 0; right: 0;
  opacity: 0;
}

/* the inverted slab that trails the detector */
.scan-wipe__band {
  top: 0;
  height: 34vh;
  -webkit-backdrop-filter: invert(1) saturate(0);
          backdrop-filter: invert(1) saturate(0);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 30%, #000 70%, transparent);
          mask-image: linear-gradient(180deg, transparent, #000 30%, #000 70%, transparent);
}
.scan-wipe.is-running .scan-wipe__band { animation: scan-band 720ms var(--ease) both; }

/* the detector itself */
.scan-wipe__line {
  top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent) 18%, #fff 50%, var(--accent) 82%, transparent);
  box-shadow: 0 0 24px rgba(225, 29, 46, .8);
}
.scan-wipe.is-running .scan-wipe__line { animation: scan-line 720ms var(--ease) both; }

/* faint acquisition grid, gone before it registers as decoration */
.scan-wipe__grid {
  top: 0; bottom: 0;
  background-image:
    repeating-linear-gradient(90deg, rgba(225, 29, 46, .07) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(0deg,  rgba(225, 29, 46, .07) 0 1px, transparent 1px 64px);
}
.scan-wipe.is-running .scan-wipe__grid { animation: scan-grid 720ms var(--ease) both; }

.scan-wipe__label {
  left: auto;
  right: var(--gutter);
  top: 22px;
  font-family: var(--font-label);
  font-size: .625rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent);
}
.scan-wipe.is-running .scan-wipe__label { animation: scan-label 720ms var(--ease) both; }

@keyframes scan-line {
  0%   { opacity: 0; transform: translateY(-4px); }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(100vh); }
}
@keyframes scan-band {
  0%   { opacity: 0; transform: translateY(-36vh); }
  16%  { opacity: .9; }
  84%  { opacity: .9; }
  100% { opacity: 0; transform: translateY(100vh); }
}
@keyframes scan-grid {
  0%, 100% { opacity: 0; }
  30%      { opacity: 1; }
  70%      { opacity: .5; }
}
@keyframes scan-label {
  0%, 100% { opacity: 0; }
  20%, 76% { opacity: 1; }
}

/* --------------------------------------------------------------------------
   Panel acquisition sweep
   -------------------------------------------------------------------------- */
.scan-pass {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms var(--ease);
  overflow: hidden;
}
.scan-pass.is-active { opacity: 1; }
.scan-pass__line {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 44%;
  background: linear-gradient(180deg, transparent, rgba(225, 29, 46, .16) 78%, rgba(225, 29, 46, .9) 100%);
  border-bottom: 1px solid var(--accent);
}
.scan-pass.is-active .scan-pass__line { animation: pass 1.9s cubic-bezier(.5, 0, .5, 1) infinite; }

/* The banner version is ambient rather than a progress signal: slower, fainter,
   and with a pause between passes so it does not pulse at you while you read. */
.scan-pass--banner .scan-pass__line {
  height: 30%;
  /* Much lighter than the panel version. Over a pale negative the panel's
     weight read as a red slab across the study — an alert, not a sweep. */
  background: linear-gradient(180deg, transparent, rgba(225, 29, 46, .04) 74%, rgba(225, 29, 46, .16) 100%);
  border-bottom-color: rgba(225, 29, 46, .45);
}
.scan-pass--banner.is-active .scan-pass__line {
  animation: pass 5.2s cubic-bezier(.45, 0, .55, 1) infinite;
}

@keyframes pass {
  0%   { transform: translateY(-46%); }
  100% { transform: translateY(230%); }
}

/* placeholders shown while a panel is still acquiring */
.slot--loading,
.roster__row--ghost,
.sched__room.is-pending {
  background: linear-gradient(90deg, #f8fafc 25%, #e2e8f0 37%, #f8fafc 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s linear infinite;
  border-radius: 8px;
  border: 0;
  color: transparent;
  min-height: 56px;
}
.roster__row--ghost { min-height: 44px; }
@keyframes shimmer {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}

/* --------------------------------------------------------------------------
   Acquisition readout
   -------------------------------------------------------------------------- */
.feed {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 12px;
  background: var(--wash);
  border-radius: 10px;
  font-size: .71875rem;
  color: var(--ink-body);
}
.feed__line {
  display: flex;
  align-items: center;
  gap: 8px;
  animation: enter 320ms var(--ease) both;
}
.feed__dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--status-ok);
  flex: none;
}
.feed__line.is-current { color: var(--ink); font-weight: 600; }
.feed__line.is-current .feed__dot {
  background: var(--accent);
  animation: throb 1s var(--ease) infinite;
}
@keyframes throb {
  0%, 100% { box-shadow: 0 0 0 0 rgba(225, 29, 46, .5); }
  50%      { box-shadow: 0 0 0 5px rgba(225, 29, 46, 0); }
}

.feed--done {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  background: transparent;
  border: 1px solid var(--line-soft);
}
.feed__tick { color: var(--status-ok); font-weight: 700; }
.feed__replay {
  margin-left: auto;
  font-size: .6875rem;
  font-weight: 600;
  color: var(--ink-muted);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.feed__replay:hover { color: var(--accent); }

/* dark panels get the readout in reverse */
.app__stage--dark + .app__side .feed,
.app__side .feed { background: var(--wash); }

/* --------------------------------------------------------------------------
   Deviation rows in the posture panel
   -------------------------------------------------------------------------- */
.metric {
  display: block;
  width: 100%;
  text-align: left;
  padding: 4px 0;
  border-radius: 6px;
  transition: opacity var(--dur) var(--ease);
}
.metric:hover { opacity: .78; }
.metric__row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-size: .78125rem;
}
.metric[aria-pressed='true'] .meter__fill { box-shadow: 0 0 0 1px var(--ink) inset; }

.leave-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
}

.app__foot__end { margin-left: auto; }

/* --------------------------------------------------------------------------
   Footer preference switches
   -------------------------------------------------------------------------- */
.pref {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--t-fine);
  color: var(--ink-muted);
  white-space: nowrap;
  transition: color var(--dur) var(--ease);
}
.pref:hover { color: var(--ink); }
.pref__dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  border: 1px solid var(--line-control);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.pref.is-on { color: var(--ink); }
.pref.is-on .pref__dot { background: var(--accent); border-color: var(--accent); }

/* --------------------------------------------------------------------------
   Account link in the header
   -------------------------------------------------------------------------- */
.account-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--t-fine);
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  transition: color var(--dur) var(--ease);
}
.account-link--plain { font-weight: 400; color: var(--ink-muted); }
.account-link:hover { color: var(--accent); }
.account-link__dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--status-ok);
}

/* --------------------------------------------------------------------------
   Smooth scrolling
   -------------------------------------------------------------------------- */
html { scroll-behavior: auto; }
html.has-smooth-scroll { scroll-behavior: auto; }  /* the loop does the easing */
@media (prefers-reduced-motion: no-preference) {
  html:not(.has-smooth-scroll) { scroll-behavior: smooth; }
}

/* --------------------------------------------------------------------------
   The reduced-motion contract
   --------------------------------------------------------------------------
   Not "slower" — absent. Content resolves to its finished state immediately.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js [data-reveal].is-in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .enter,
  .feed__line,
  .scan-pass.is-active .scan-pass__line,
  .slot--loading,
  .roster__row--ghost,
  .sched__room.is-pending,
  .view {
    animation: none !important;
  }
  .slot--loading, .roster__row--ghost, .sched__room.is-pending { background: #f8fafc; }
  .xray, .scan-wipe { display: none !important; }
  html { scroll-behavior: auto !important; }
}
