/* ============================================================
   RCM portal motion layer, styles.  V3.1, additive only.

   Loaded after globals.css from the root layout. This file never
   edits a component or its markup: every rule either targets a
   class the host already renders, or an element this layer's own
   JS created. Delete the <link> and the <script> in layout.tsx and
   the portal reverts completely, with no other change needed.

   Adapted from the MECSR election kit's enhance.css. The kit's
   styles.css was deliberately NOT adopted: its navy and purple
   palette and Poppins headings conflict with this portal's emerald
   identity and Fraunces headings, and the portal already has its
   own token system. Motion only.

   Colours come from the portal's semantic tokens. There is no
   --shadow token here as there is in the kit, so elevation is
   derived from --ink with color-mix, which holds in both themes.
   ============================================================ */

/* ---------- scroll progress ---------- */
#rcm-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 0;
  /* Under the impersonation banner (z-50), not across it. */
  z-index: 45;
  pointer-events: none;
  /* Accent to brand, in that order, in both themes: the light theme's
     --brand-strong is nearly black, which inverted the bar's identity. */
  background: linear-gradient(90deg, var(--accent), var(--brand));
  transition: width 0.12s linear;
}
html[data-theme="dark"] #rcm-progress {
  background: linear-gradient(90deg, var(--accent), var(--brand-strong));
}
/* The rail is fixed and never scrolls, so the bar does not run over it. */
@media (min-width: 1024px) {
  #rcm-progress {
    left: 15rem;
  }
}

/* ---------- header condense past ~40px ----------
   The portal's persistent header is the shell's fixed mobile bar
   (the desktop chrome is the rail, which does not scroll). Targeted
   by the utility classes it already carries, so no markup changes. */
.fixed.inset-x-0.top-0.z-30 {
  transition: box-shadow 0.35s ease;
}
/* The shadow only: the bar is fully opaque in both themes, so the
   backdrop filter had nothing to blur and only forced a compositing
   layer on every scroll in the phone-first ops app. */
.fixed.inset-x-0.top-0.z-30.rcm-condensed {
  box-shadow: 0 4px 24px -10px color-mix(in oklab, var(--ink) 30%, transparent);
}
/* Dark carries its own, as the kit does: the same shadow reads as
   nothing against a dark surface. */
html[data-theme="dark"] .fixed.inset-x-0.top-0.z-30.rcm-condensed {
  box-shadow: 0 4px 24px -10px color-mix(in oklab, black 65%, transparent);
}

/* ---------- card hover lift ----------
   LINKS ONLY. Hover elevation is the universal "this is clickable"
   signal, so it may only appear on something that is. The directory's
   company cards were in this list and contain no link at all: they
   lifted and promised a click that did nothing. The generic Card
   section is left alone too, since lifting every panel on a dense
   working screen is noise, not polish.

   data-motion-scope="gala" is set by the JS on the seating planner,
   where the plan is a precision tool and nothing may move under the
   pointer. */
html:not([data-motion-scope="gala"]) a.rounded-lg.border.bg-surface-1 {
  transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.18s ease, border-color 0.18s ease;
}
html:not([data-motion-scope="gala"]) a.rounded-lg.border.bg-surface-1:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 28px -16px color-mix(in oklab, var(--ink) 45%, transparent);
}
/* A shadow of black on a near-black surface is invisible, so the dark
   theme lifts the border instead: the transition already declared
   border-color and nothing was ever changing it. */
html[data-theme="dark"]:not([data-motion-scope="gala"]) a.rounded-lg.border.bg-surface-1:hover {
  box-shadow: 0 12px 28px -16px color-mix(in oklab, black 70%, transparent);
  border-color: color-mix(in oklab, var(--accent) 45%, var(--border));
}

/* ---------- button ripple ----------
   The clipping context is added by the JS for the ripple's lifetime
   and removed afterwards, so no button carries a permanent overflow
   change. An outline-drawn focus ring is not clipped by overflow in
   any case, and the focus check in the verification proves it. */
.rcm-rippling {
  position: relative;
  overflow: hidden;
}
.rcm-ripple {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  transform: scale(0);
  opacity: 0.55;
  background: color-mix(in oklab, var(--accent) 55%, transparent);
  animation: rcm-ripple 0.6s ease-out forwards;
}
html[data-theme="dark"] .rcm-ripple {
  background: color-mix(in oklab, var(--brand-strong) 40%, transparent);
}
@keyframes rcm-ripple {
  to {
    transform: scale(2.6);
    opacity: 0;
  }
}

/* ---------- count-up ----------
   The number is written by the host; this only holds its width
   steady while it counts, so nothing beside it jumps. */
.rcm-counting {
  font-variant-numeric: tabular-nums;
}

/* ---------- reduced motion ----------
   Everything decorative is dropped. The progress bar keeps its
   position (it is information, not decoration) and loses only its
   transition. */
@media (prefers-reduced-motion: reduce) {
  #rcm-progress {
    transition: none;
  }
  .rcm-ripple {
    display: none;
  }
  html:not([data-motion-scope="gala"]) a.rounded-lg.border.bg-surface-1,
    .fixed.inset-x-0.top-0.z-30 {
    transition: none;
  }
  html:not([data-motion-scope="gala"]) a.rounded-lg.border.bg-surface-1:hover {
    transform: none;
  }
}
