@charset "UTF-8";
/* GymX — the sign-in screens: a bright room with gym kit drifting through it.
   Developed by X IT — xitbd.com

   Built from the brand tokens (--volt, --flame) rather than fixed colours, so a
   gym that changes its palette in Settings gets a matching backdrop for free.

   Only transform and opacity are animated — both composite on the GPU, so this
   costs nothing on the mid-range Android a member is actually holding.

   Both sign-in pages were built dark, and set white text in three places. Those
   are overridden here rather than left to disappear against a light room. */

/* ------------------------------------------------------------------- room */

.auth-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background:
    /* two soft brand washes, then the paper the room is printed on */
    radial-gradient(70% 55% at 8% 4%,
      color-mix(in srgb, var(--volt) 30%, transparent) 0%, transparent 60%),
    radial-gradient(60% 55% at 96% 96%,
      color-mix(in srgb, var(--flame) 20%, transparent) 0%, transparent 62%),
    linear-gradient(155deg, #FFFFFF 0%, #F7FAF4 45%, #EDF2E8 100%);
}

/* A wide sheen that crosses the room every so often, like sun through the
   window. Long gap, short pass — a moment, not a strobe. */
.auth-bg::after {
  content: '';
  position: absolute;
  top: -50%; bottom: -50%;
  width: 40%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .85), transparent);
  transform: translate3d(-160%, 0, 0) rotate(9deg);
  animation: sheen 13s ease-in-out infinite;
  animation-delay: 3s;
}
@keyframes sheen {
  0%, 66%  { transform: translate3d(-160%, 0, 0) rotate(9deg); }
  100%     { transform: translate3d(360%, 0, 0) rotate(9deg); }
}

/* The page content sits above the room. */
.auth-wrap, .auth { position: relative; z-index: 1; }
.auth-wrap { background: transparent; }

/* --------------------------------------------------------------- the kit */

.eq-defs { position: absolute; width: 0; height: 0; }

.eq {
  position: absolute;
  color: #14171A;                 /* the colour the symbols inherit */
  fill: currentColor;
  opacity: .13;
  will-change: transform;
}

/* Three drift paths. Each piece gets one, at its own speed and phase, so
   nothing ever moves in step with anything else. */
@keyframes floatA {
  0%   { transform: translate3d(0, 0, 0)          rotate(0deg); }
  50%  { transform: translate3d(3vw, -7vh, 0)     rotate(22deg); }
  100% { transform: translate3d(0, 0, 0)          rotate(0deg); }
}
@keyframes floatB {
  0%   { transform: translate3d(0, 0, 0)          rotate(0deg); }
  50%  { transform: translate3d(-4vw, 6vh, 0)     rotate(-26deg); }
  100% { transform: translate3d(0, 0, 0)          rotate(0deg); }
}
@keyframes floatC {
  0%   { transform: translate3d(0, 0, 0)          rotate(-8deg); }
  50%  { transform: translate3d(2.5vw, 8vh, 0)    rotate(14deg); }
  100% { transform: translate3d(0, 0, 0)          rotate(-8deg); }
}

/* A slow tumble across the whole width, for the two heavy pieces — it gives
   the field somewhere to go rather than everything bobbing on the spot. */
@keyframes crossing {
  0%   { transform: translate3d(-16vw, 0, 0) rotate(0deg); }
  100% { transform: translate3d(116vw, 0, 0) rotate(300deg); }
}

/* left / top / size / animation / delay, all deliberately uneven.
   Negative delays start each piece part-way in, so the field is already
   scattered on the first frame instead of everything launching together. */
.eq.e1  { left:  6%; top:  9%; width: 104px; animation: floatA 26s ease-in-out infinite; animation-delay: -3s;  }
.eq.e2  { left: 17%; top: 62%; width:  78px; animation: floatB 31s ease-in-out infinite; animation-delay: -11s; }
.eq.e3  { left: 79%; top: 13%; width:  92px; animation: floatC 35s ease-in-out infinite; animation-delay: -6s;  }
.eq.e4  { left: 68%; top: 74%; width: 132px; animation: floatA 29s ease-in-out infinite; animation-delay: -17s; }
.eq.e5  { left: 31%; top: 25%; width:  70px; animation: floatB 38s ease-in-out infinite; animation-delay: -21s; opacity: .08; }
.eq.e6  { left: 88%; top: 45%; width:  62px; animation: floatC 24s ease-in-out infinite; animation-delay: -8s;  }
.eq.e7  { left:  3%; top: 40%; width:  86px; animation: floatA 33s ease-in-out infinite; animation-delay: -14s; }
.eq.e8  { left: 47%; top: 86%; width:  56px; animation: floatB 27s ease-in-out infinite; animation-delay: -4s;  opacity: .09; }
.eq.e9  { left: 92%; top: 78%; width:  74px; animation: floatC 30s ease-in-out infinite; animation-delay: -19s; }
.eq.e10 { left: 12%; top: 88%; width:  64px; animation: floatA 36s ease-in-out infinite; animation-delay: -9s;  }
.eq.e11 { left: 58%; top:  5%; width:  54px; animation: floatB 28s ease-in-out infinite; animation-delay: -23s; opacity: .08; }
.eq.e12 { left: 40%; top: 50%; width:  58px; animation: floatC 32s ease-in-out infinite; animation-delay: -2s;  opacity: .07; }

/* The two that cross the room. Placed off-screen; the animation carries them. */
.eq.e13 { left: 0; top: 30%; width: 118px; animation: crossing 46s linear infinite; animation-delay: -12s; opacity: .09; }
.eq.e14 { left: 0; top: 67%; width:  76px; animation: crossing 61s linear infinite; animation-delay: -40s; opacity: .08; }

/* A little colour in the field so it is not fourteen grey blobs. */
.eq.e2, .eq.e9  { color: color-mix(in srgb, var(--volt)  55%, #14171A); opacity: .16; }
.eq.e4, .eq.e13 { color: color-mix(in srgb, var(--flame) 45%, #14171A); opacity: .12; }
.eq.e7          { color: color-mix(in srgb, var(--volt)  40%, #14171A); opacity: .14; }

/* -------------------------------------------------------- light-room text */

/* Both pages were written for a dark background. On paper, white text is gone. */
.auth-brand { color: var(--ink); }
.auth-brand .mark {
  background: var(--volt);
  color: var(--ink);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--volt) 55%, transparent);
}

.auth-foot { color: #5E6A65; }
.auth-foot a { color: #3D4642; }

/* A white card on near-white paper needs an edge and a softer, wider shadow —
   the heavy dark-background drop shadow reads as dirt here. */
.auth-card {
  border: 1px solid rgba(20, 23, 26, .07);
  box-shadow: 0 2px 6px rgba(20, 23, 26, .05), 0 18px 44px rgba(20, 23, 26, .13);
}

/* --------------------------------------------------------------- entrance */

.auth-brand { animation: rise .5s cubic-bezier(.2, .7, .3, 1) both; }
.auth-card  { animation: rise .6s cubic-bezier(.2, .7, .3, 1) .06s both; }
.auth-foot  { animation: rise .6s cubic-bezier(.2, .7, .3, 1) .14s both; }

@keyframes rise {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------- rotating line */

/* Member side only. A line that changes while you type your password is a
   small thing, but it is the difference between a login box and a gym. */
.hype {
  height: 1.5rem;
  line-height: 1.5rem;
  margin: 0 0 17px;
  text-align: center;
  position: relative;
  font-size: .86rem;
  font-weight: 800;
  letter-spacing: .01em;
  /* Sits on pale paper, so it needs real weight and a real colour — the grey
     it started as was legible but looked like disabled text. */
  color: #2F3A35;
}
.hype span {
  position: absolute;
  inset: 0;
  opacity: 0;
  animation: hype 21s linear infinite;
}
.hype span:nth-child(1) { animation-delay:  0s; }
.hype span:nth-child(2) { animation-delay:  3s; }
.hype span:nth-child(3) { animation-delay:  6s; }
.hype span:nth-child(4) { animation-delay:  9s; }
.hype span:nth-child(5) { animation-delay: 12s; }
.hype span:nth-child(6) { animation-delay: 15s; }
.hype span:nth-child(7) { animation-delay: 18s; }

/* Seven lines share one 21s loop: each is up for about three seconds, with a
   short cross-fade at either end, so exactly one is ever on screen. */
@keyframes hype {
  0%      { opacity: 0; transform: translate3d(0, 6px, 0); }
  2%, 12% { opacity: 1; transform: none; }
  14%     { opacity: 0; transform: translate3d(0, -6px, 0); }
  100%    { opacity: 0; }
}

/* ---------------------------------------------------------- small screens */

@media (max-width: 560px) {
  /* Fewer pieces on a narrow screen — the ones that would end up behind the
     card are clutter rather than atmosphere. The rest keep their weight. */
  .eq.e5, .eq.e11, .eq.e12 { display: none; }
  .auth-bg::after { display: none; }
}

/* --------------------------------------------------------- reduced motion */

/* Someone who has asked their device for less motion keeps the room and the
   kit, and loses the movement. It still looks like something. */
@media (prefers-reduced-motion: reduce) {
  .auth-bg::after,
  .eq,
  .auth-brand,
  .auth-card,
  .auth-foot,
  .hype span {
    animation: none !important;
  }
  .auth-bg::after { display: none; }
  /* The two crossing pieces are parked off-screen without their animation, so
     they are given a resting place on the page instead. */
  .eq.e13 { transform: translate3d(22vw, 0, 0) rotate(18deg); }
  .eq.e14 { transform: translate3d(74vw, 0, 0) rotate(-12deg); }
  .hype span { opacity: 0; }
  .hype span:first-child { opacity: 1; }
}

/* ---------------------------------------------------------------------------
   Sign-in layout.

   This lived as an inline <style> in admin/login/index.php until locked.php
   needed exactly the same room. Two copies would have drifted, so it moved
   here and is scoped to body.auth-page — the class both pages set — rather
   than to bare body, which would have reached every panel screen.

   Layout only; the colours are the light treatment above. The paper-coloured
   background is a fallback so the page is still legible if this file fails
   to load.
   --------------------------------------------------------------------------- */
body.auth-page {
  background: #F7FAF4;
  display: grid;
  place-items: center;
  min-height: 100vh;
  padding: 22px;
}
body.auth-page .auth { width: 100%; max-width: 392px; }
body.auth-page .auth-brand {
  display: flex; align-items: center; gap: .6rem;
  font-weight: 900; font-size: 1.22rem; letter-spacing: -.035em;
  justify-content: center; margin-bottom: 20px;
}
body.auth-page .auth-brand .mark {
  width: 34px; height: 34px; border-radius: 10px;
  background: var(--volt); color: var(--ink);
  display: grid; place-items: center; font-size: 1.05rem;
}
body.auth-page .auth-card {
  background: #fff; border-radius: 18px; padding: clamp(22px, 4vw, 30px);
}
body.auth-page .auth-card h1 { font-size: 1.28rem; letter-spacing: -.03em; margin-bottom: 4px; }
body.auth-page .auth-card .sub { color: var(--muted); font-size: .88rem; margin-bottom: 20px; }
body.auth-page .auth-foot {
  text-align: center; font-size: .78rem; margin-top: 18px; line-height: 1.7;
}
body.auth-page .auth-foot a { text-decoration: underline; text-underline-offset: 2px; }
body.auth-page .code-inp {
  font-family: var(--mono); font-size: 1.45rem; letter-spacing: .42em;
  text-align: center; padding: .6rem;
}
