/* ============================================================
   VegasBet - Auth hero panel (login & register)

   The left half of the auth card: a stadium photo under a purple
   grade, with a calm set of loops over it. auth.css owns the card
   frame and the form panel; everything `.auth-hero*` lives here.

   Rules this file is built to:
     - every LOOPING animation moves transform or opacity only, and
       none of them cycles faster than 4s;
     - the one-shot intro is the only place `filter` is animated;
     - no particles, no flicker, no canvas, no libraries.
   ============================================================ */

.auth-hero {
  /* -- Photo framing --------------------------------------------
     The master is a 9:16 portrait, at least as tall as every panel, so
     `cover` always fills the WIDTH and the Y of object-position is what
     chooses the crop (X never bites). The values here are the register
     page's, where the panel is nearly 9:16 itself and almost the whole
     frame shows; the login panel and the mobile banner are squarer and
     pick their own window further down. In the master the head sits at
     33-46% of the height and the torso at 48-70%, with the top third
     empty stadium roof - so a squarer panel crops that roof away and
     lifts the face up beside the logo. */
  --hero-pos-x: 50%;
  --hero-pos-y: 60%;

  /* -- Tint mask -------------------------------------------------
     An ellipse of clear photo over the player, fading to fully
     tinted at the panel edges. Retune these five to follow a
     different photo - nothing else has to move. The player stands
     left of centre in this frame (face ~35% across). */
  --hero-mask-w: 32%;
  --hero-mask-h: 40%;
  --hero-mask-x: 37%;
  --hero-mask-y: 48%;
  --hero-mask-clear: 40%;   /* untouched out to this much of the ellipse */

  /* -- Breathing origin: the torso, so the scale reads as the camera
     easing in on the player rather than on the panel. */
  --hero-breathe-x: 38%;
  --hero-breathe-y: 58%;

  /* -- Diagonal sheen. ONE flag: set --hero-sheen to `none` and the
     layer - and its animation - is gone. --hero-sheen-peak caps how
     bright the pass ever gets. */
  --hero-sheen: block;
  --hero-sheen-peak: 0.12;

  /* -- Parallax, written by auth-hero.js. Left at (0,0) unless a fine
     pointer is actually moving over the panel.
     --hero-bleed is how far the photo hangs outside the panel on every
     side. It MUST stay larger than the drift, or a shifted photo uncovers
     a strip of bare panel along the opposite edge - the breathing cannot
     be relied on to hide it, because that animation passes through scale
     1.0 twice a cycle. auth-hero.js reads this value and clamps its own
     drift to it, so lowering it here can never reopen that gap. */
  --mx: 0px;
  --my: 0px;
  --hero-bleed: 12px;

  /* -- Palette. The globals carry the purples; these two deep shades
     are local to the panel. */
  --hero-deep: #2a0f55;
  --hero-ink: #0e071c;

  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding: 44px 40px;
  min-height: 560px;
  display: flex;
  flex-direction: column;
  /* Logo pinned to the top, copy and badge sitting together at the bottom.
     This used to be space-between, which centred the copy - and centred is
     exactly where the bottom scrim has run out, so white 38px type landed
     on lit crowd at 1.9:1. Down here it clears AA on the photo's brightest
     pixel with room to spare, and it also puts more clear photo between the
     player's face and the first line of text. */
  justify-content: flex-end;
  gap: 30px;
  /* Outer corners only - the inner edge stays square against the form
     panel. The card clips as well, but a hero that rounds itself
     survives its own media stack's overflow. */
  border-radius: 24px 0 0 24px;
  /* Shows for the instant before the photo paints, and stays the
     backdrop if it never does. */
  background:
    radial-gradient(700px 380px at 20% 0%, rgba(124, 58, 237, 0.42), transparent 62%),
    linear-gradient(160deg, var(--hero-deep) 0%, #16121f 60%, var(--hero-ink) 100%);
}

/* The login panel is 560px next to a short form - squarer than the frame,
   so only ~66% of the photo's height fits. Window it so the roof goes and
   the head comes up level with the logo mark (they never overlap: the mark
   ends at x 85px, the head starts past 130px), which leaves the whole gap
   above the title for the shoulders instead of the chin. Same photo, same
   files - only the window moves, so a tab switch still shows one panel. */
.auth-card[data-auth-mode="login"] .auth-hero {
  --hero-pos-y: 76%;
  --hero-mask-y: 30%;
  --hero-mask-h: 46%;
  --hero-breathe-y: 46%;
}

/* -- Media stack -----------------------------------------------
   Isolated so `color` / `screen` blend against the photo and stop
   there. Absolutely positioned, so none of it can shift layout: the
   panel is exactly as tall with the photo as without it. */
.auth-hero-media {
  position: absolute;
  inset: 0;
  overflow: hidden;
  isolation: isolate;
  border-radius: inherit;
  pointer-events: none;
}

/* Layer 1 - the photo. The <picture> carries the parallax offset and
   the <img> inside it carries the intro and the breathing, so the two
   never fight over `transform`. */
.auth-hero-frame {
  position: absolute;
  inset: calc(var(--hero-bleed) * -1);
  display: block;
  transform: translate3d(var(--mx), var(--my), 0);
}

.auth-hero-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--hero-pos-x) var(--hero-pos-y);
  transform-origin: var(--hero-breathe-x) var(--hero-breathe-y);
  /* Two animations, in this order on purpose: the intro keeps `filter`
     and `opacity` under its `both` fill once it ends, while the later
     breathing wins `transform` - which is exactly the hand-off wanted.
     Breathing does not start until the intro is over (1.2s delay), and
     an animation still inside its delay contributes nothing. */
  animation:
    authHeroPhotoIn 1.2s cubic-bezier(0.22, 0.8, 0.28, 1) both,
    authHeroBreathe 16s ease-in-out 1.2s infinite alternate;
}

/* Layer 2 - purple tint. `color` transfers hue and saturation only, so
   the photo keeps its own light and shade; the mask lifts it back off
   the player so he stays in natural colour. */
.auth-hero-tint {
  position: absolute;
  inset: 0;
  opacity: 0.85;
  mix-blend-mode: color;
  background: linear-gradient(155deg,
      var(--purple-light) 0%,
      var(--purple) 45%,
      var(--hero-deep) 100%);
  -webkit-mask-image: radial-gradient(ellipse var(--hero-mask-w) var(--hero-mask-h)
      at var(--hero-mask-x) var(--hero-mask-y), transparent var(--hero-mask-clear), #000 100%);
          mask-image: radial-gradient(ellipse var(--hero-mask-w) var(--hero-mask-h)
      at var(--hero-mask-x) var(--hero-mask-y), transparent var(--hero-mask-clear), #000 100%);
}

/* Layer 3 - two soft purple blooms along the top edge.

   Two things about them are load-bearing. Radii are PERCENTAGES of the
   panel, not pixels: it is 560px tall next to the sign-in form, ~820px
   next to the register form and 440px once it stacks, and a bloom fixed
   in px covers that last one corner to corner. And they are FAINT and
   sit high - screen-blending anything stronger over a photograph is not
   a glow, it is a haze, and the first thing it washes out is the face
   (which is the one part of the frame the tint mask works to keep). */
.auth-hero-glow {
  position: absolute;
  inset: 0;
  mix-blend-mode: screen;
  opacity: 0.55;
  background:
    radial-gradient(96% 34% at 20% -16%, rgba(157, 93, 245, 0.30), transparent 72%),
    radial-gradient(58% 26% at 88% -6%, rgba(168, 85, 247, 0.22), transparent 74%);
  animation: authHeroGlow 6s ease-in-out infinite alternate;
}

/* Layer 4 - darkening. Top ~22% for the logo, a bottom ramp to ~66% for
   the copy, a vignette to close the edges.

   The ramp's stops are placed against MEASURED contrast, not by eye: the
   copy occupies 21%-63% of the panel height from the bottom, and on the
   photo's brightest pixel under it white 38px type reads at 9:1 (AA asks
   3:1). An earlier, brighter frame needed this ramp up at 78%; the 9:16
   master's lower third is shadowed pitch, so the ramp is back at the
   height the brief asked for and the face - which starts at ~70% on the
   login window - sits fully outside it. */
.auth-hero-scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      rgba(14, 7, 28, 0.74) 0%,
      rgba(14, 7, 28, 0.30) 12%,
      transparent 22%),
    linear-gradient(0deg,
      rgba(14, 7, 28, 0.94) 0%,
      rgba(14, 7, 28, 0.84) 24%,
      rgba(14, 7, 28, 0.50) 46%,
      rgba(14, 7, 28, 0.18) 58%,
      transparent 66%),
    radial-gradient(125% 105% at 50% 42%, transparent 42%, rgba(14, 7, 28, 0.58) 100%);
}

/* Layer 5 - one diagonal pass, well under anything you would call a
   flash: 2.5s of travel out of a 12.5s cycle, peaking at the flag. */
.auth-hero-sheen {
  display: var(--hero-sheen, block);
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: 0;
  right: 0;
  opacity: 0;
  mix-blend-mode: screen;
  background: linear-gradient(115deg,
      transparent 38%,
      rgba(214, 190, 255, 0.55) 50%,
      transparent 62%);
  animation: authHeroSheen 12.5s linear infinite;
}

/* -- Content ---------------------------------------------------
   Everything below paints after the media stack, so no blend layer
   reaches it. */
.auth-hero-logo {
  position: relative;
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  margin-bottom: auto;   /* holds the top while the rest sits at the bottom */
}

.auth-hero-logo-img {
  height: 44px;
  width: auto;
  filter: drop-shadow(0 0 18px rgba(168, 85, 247, 0.55));
}

.auth-hero-main { position: relative; }

.auth-hero-title {
  font-family: 'Space Grotesk', 'Inter', sans-serif;
  font-size: 38px;
  line-height: 1.08;
  font-weight: 700;
  margin: 0 0 14px;
  color: #fff;
  text-shadow: 0 2px 18px rgba(14, 7, 28, 0.75);
}

.auth-hero-sub {
  margin: 0;
  font-size: 15px;
  line-height: 1.6;
  /* Lightened from the flat-gradient era: this sits over a photo now,
     and AA has to hold on the brightest patch the scrim lets through. */
  color: #ded8ec;
  max-width: 340px;
  text-shadow: 0 1px 12px rgba(14, 7, 28, 0.8);
}

.auth-stats {
  display: flex;
  gap: 26px;
  margin-top: 34px;
}

.auth-stat-num {
  font-family: 'Space Grotesk', 'Inter', sans-serif;
  font-size: 26px;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 2px 14px rgba(14, 7, 28, 0.7);
}

.auth-stat-label {
  font-size: 12px;
  color: #b3abc4;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-shadow: 0 1px 10px rgba(14, 7, 28, 0.8);
}

.auth-stat-div {
  width: 1px;
  background: rgba(255, 255, 255, 0.14);
}

.auth-secure {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-radius: 14px;
  /* Opaque enough to read over the photo, where the old translucent
     plate would have shown grass through the text. */
  background: rgba(9, 26, 21, 0.62);
  border: 1px solid rgba(52, 211, 153, 0.3);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-size: 13px;
  color: #cbe9dc;
  font-weight: 600;
}

.auth-secure-dot {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #34d399;
  box-shadow: 0 0 10px #34d399;
  animation: authLivePulse 4s ease-in-out infinite;
}

/* -- Intros ----------------------------------------------------
   The copy is the only thing that differs between the two tabs. On a
   first visit it rises in behind the photo; on a tab switch
   auth-hero.js marks the panel `is-resumed` and it becomes a plain
   200ms crossfade while the loops behind it carry on mid-cycle. */
.auth-hero-copy {
  animation: authHeroCopyIn 0.5s ease 0.6s both;
}

.auth-hero.is-resumed .auth-hero-copy {
  animation: authHeroCopyFade 0.2s linear both;
}

/* A resumed panel skips the photo intro outright - replaying a 1.2s
   fade-and-unblur on every tab click is the restart this is trying to
   avoid. Breathing is restated without its delay so the negative
   animation-delay the script sets can carry it on in phase. */
.auth-hero.is-resumed .auth-hero-photo {
  opacity: 1;
  filter: saturate(0.8) contrast(1.08) brightness(0.82);
  animation: authHeroBreathe 16s ease-in-out infinite alternate;
}

/* -- Keyframes -------------------------------------------------
   `filter` is animated in exactly one place: the one-shot intro,
   which the brief asks for by name. Every loop below is transform or
   opacity only. */
@keyframes authHeroPhotoIn {
  from {
    opacity: 0;
    transform: scale(1.08);
    filter: saturate(0.8) contrast(1.08) brightness(0.82) blur(6px);
  }
  to {
    opacity: 1;
    transform: scale(1);
    filter: saturate(0.8) contrast(1.08) brightness(0.82) blur(0);
  }
}

@keyframes authHeroBreathe {
  from { transform: scale(1); }
  to   { transform: scale(1.04); }
}

@keyframes authHeroGlow {
  from { opacity: 0.55; }
  to   { opacity: 0.9; }
}

@keyframes authHeroSheen {
  0%   { transform: translate3d(-140%, 0, 0); opacity: 0; }
  4%   { opacity: var(--hero-sheen-peak, 0.12); }
  16%  { opacity: var(--hero-sheen-peak, 0.12); }
  20%  { transform: translate3d(140%, 0, 0); opacity: 0; }
  100% { transform: translate3d(140%, 0, 0); opacity: 0; }
}

@keyframes authHeroCopyIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes authHeroCopyFade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes authLivePulse {
  0%, 100% { opacity: 1;    box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.5); }
  50%      { opacity: 0.55; box-shadow: 0 0 0 5px rgba(52, 211, 153, 0); }
}

/* -- Responsive ------------------------------------------------
   Once the card stacks, the panel sits ABOVE the form as a banner.
   The stats go (there is no room for them at 440px) and the crop
   shifts so the face lands in the clear band between the logo and the
   copy rather than behind either of them. */
@media (max-width: 860px) {
  /* Written against the per-page selector so it outranks the login
     window above at the same specificity - both tabs share this banner
     framing once the card stacks.

     370px, not the 440px the brief first asked for: on a phone the banner
     sits ABOVE the form, and every pixel of it pushes the first input
     further under the fold - at 440px a register visitor saw two fields.
     The Secured plaque goes (owner call, 2026-09-11) and the panel gives
     back exactly its height plus the gap above it.

     The window is chosen for the WIDEST banner (460px, where only 45% of
     the frame fits): 50% keeps the hairline inside the panel there and,
     at 375px where 65% fits, still lands the face between the logo mark
     and the title. Higher values clip the top of the head at 460px. */
  .auth-card[data-auth-mode] .auth-hero {
    --hero-pos-y: 50%;
    --hero-mask-x: 36%;
    --hero-mask-y: 34%;
    --hero-mask-w: 36%;
    --hero-mask-h: 42%;
    --hero-breathe-y: 48%;
    min-height: 0;
    height: 370px;
    padding: 24px 26px 26px;
    border-radius: 24px 24px 0 0;
  }

  .auth-hero-title { font-size: 30px; }
  .auth-hero-sub { font-size: 14px; max-width: none; }
  .auth-stats { display: none; }
  .auth-secure { display: none; }

  /* The copy now occupies the bottom ~40% of a 370px banner, so the ramp
     stops at 58% - any higher and it starts dimming the chin, which sits
     at ~56% from the bottom on the widest banner. */
  .auth-hero-scrim {
    background:
      linear-gradient(180deg,
        rgba(14, 7, 28, 0.78) 0%,
        rgba(14, 7, 28, 0.32) 14%,
        transparent 26%),
      linear-gradient(0deg,
        rgba(14, 7, 28, 0.94) 0%,
        rgba(14, 7, 28, 0.86) 22%,
        rgba(14, 7, 28, 0.50) 40%,
        rgba(14, 7, 28, 0.15) 50%,
        transparent 58%),
      radial-gradient(130% 110% at 50% 38%, transparent 40%, rgba(14, 7, 28, 0.6) 100%);
  }
}

/* The height stays 440px down here on purpose - the panel is the reason
   this page has a photo, and shrinking it on the narrowest screens is
   where it would stop reading as one. Only the chrome inside it gives
   ground. */
@media (max-width: 480px) {
  /* Same selector shape as the 860px block, or its padding outranks this
     one and the Secured plaque wraps onto two lines at 375px. */
  .auth-card[data-auth-mode] .auth-hero {
    padding: 20px 20px 22px;
  }
  .auth-hero-logo-img { height: 36px; }
  .auth-hero-title { font-size: 26px; }
}

/* -- Reduced motion --------------------------------------------
   Everything stops, the parallax included - auth-hero.js reads the
   same query and never attaches its listeners. The photo is left in
   its finished state (visible, unblurred, unscaled), not hidden. */
@media (prefers-reduced-motion: reduce) {
  .auth-hero-photo,
  .auth-hero-glow,
  .auth-hero-sheen,
  .auth-hero-copy,
  .auth-secure-dot {
    animation: none !important;
  }

  .auth-hero-photo {
    opacity: 1;
    transform: none;
    filter: saturate(0.8) contrast(1.08) brightness(0.82);
  }

  .auth-hero-frame { transform: none; }
  .auth-hero-sheen { display: none; }
}
