/* =====================================================================
   VCM LOGIN SCREEN  -  animated devotional welcome / sign-in
   (markup + behaviour: auth/auth-login-screen.js)
   ---------------------------------------------------------------------
   Everything here is scoped under .vc-login, so no other screen can be
   affected. The screen is a DOM overlay inside .app (same model as the
   Settings / About popups), so on desktop it sits INSIDE the centred
   phone frame, and nav/back-nav.js treats it as the top-most layer.

   SIZING
   - phones (<600px): the overlay is fixed to the screen itself, so it is
     always full-screen and never depends on how tall the calendar
     underneath happens to be (no page scrolling beneath the login).
   - desktop (>=600px): the overlay is exactly the .app phone frame (see
     "Desktop phone-frame" below).
   In both cases the login card is centred on the KBS badge (see "scene
   geometry" and ".vc-login-card"); if its content is ever taller than the
   screen / frame (Create Account on a very small phone, phone panel +
   error open) the card scrolls inside itself instead of being clipped.

   STAGED REVEAL
   Every animated element carries class .vc-reveal plus a data-step
   name. The delay of each step is set ONCE, in the "TIMELINE" block
   below - change a number there to re-time the whole sequence:

     step  1  cosmic background        (0.0s: fade / slow push-in of the
                                        stars, rays, beams and halo)
     step  2  KBS logo + golden orbit  (0.5s / 0.8s: fade + a small rise;
                                        the orbit then turns for good)
     step  3  "Hare Krishna"           (1.5s)
              "Welcome"                (1.8s)
              "Vaishnava Calendar Myanmar" (2.1s)
              "A Devotional Offering By Krishna Bhakti Sanga" (2.4s)
     step  4  login card               (2.7s)
     step  5  the controls inside it   (3.1s - 3.85s, one after another:
                                        Email, Password, Login (+ links),
                                        Create account, Google Account)
     (then)   Continue as Guest        (4.0s, only while the guest flag is on)

   Elements stay visibility:hidden until their step, so keyboard focus
   can never land on something that is not on screen yet. A tap / key
   press adds .is-instant (fast-forward), and prefers-reduced-motion
   skips the sequence entirely. The base (un-animated) state of every
   element is fully visible, so if animations are unavailable the
   screen is still complete and usable.

   The login card, Google and Phone buttons are always dark-themed
   (a cinematic scene) - they intentionally do not follow the app's
   light/dark theme toggle.
   ===================================================================== */


/* ---------------------------------------------------------------------
   Overlay shell
   --------------------------------------------------------------------- */

.special-days-overlay.vc-login {

    /* scoped palette - taken from the KBS logo (navy ring, gold line,
       cream face) */
    --vc-navy-0: #050810;
    --vc-navy-1: #0a1426;
    --vc-navy-2: #12294a;
    --vc-gold: #d6b26e;
    --vc-gold-hi: #f0d28f;
    --vc-gold-lo: #b98f45;
    --vc-cream: #f4ecd8;
    --vc-text: #f4f6f8;
    --vc-muted: rgba(244, 236, 216, 0.74);

    /* the dark navy / midnight night sky (background base) - dark on
       purpose, so the golden rays and the badge carry the scene */
    --vc-scene-top: #050f28;
    --vc-scene-mid: #02071a;
    --vc-scene-low: #010411;

    /* phones: pinned to the screen. left/right keep it inside the 440px
       app column on the 441-599px widths where .app is centred with
       gutters; on real phones (<=440px) they resolve to 0. The desktop
       block below switches this back to "inside .app". */
    position: fixed;
    top: 0;
    bottom: 0;
    left: max(0px, calc(50% - 220px));
    right: max(0px, calc(50% - 220px));

    /* override the generic centred-popup layout of .special-days-overlay */
    display: block;
    padding: 0;
    overflow: hidden;

    background: var(--vc-navy-0);
    color: var(--vc-text);

    /* SCENE GEOMETRY - the one source of truth for the badge, the orbit and
       the login card, so they stay concentric at any screen size.
       The overlay is a size container: cqw / cqh below are the FRAME's own
       width / height (the phone screen, or the phone frame on desktop).
         --vc-head    room kept free above the badge for the greeting
         --vc-emblem  diameter of the KBS badge: 88% of the frame width (the
                      mantra ring and the gold orbit ring then still fit
                      inside the frame), but never so big that the greeting
                      no longer fits above it.
       The first pair is the fallback for browsers without container units. */
    container-type: size;
    --vc-head: clamp(96px, 20vh, 168px);
    --vc-emblem: min(88vw, 387px, calc(100vh - 2 * var(--vc-head)));

    animation: vc-login-overlay-in 0.6s ease both;
}

@supports (width: 1cqw) {

    .special-days-overlay.vc-login {
        --vc-head: clamp(96px, 21cqh, 168px);
        --vc-emblem: min(88cqw, calc(100cqh - 2 * var(--vc-head)));
    }
}

/* Startup (native cold start, nobody signed in): the shell is opaque on its
   very first frame instead of fading in over the calendar. MUST stay above
   .is-leaving (same specificity, later wins) so the exit fade still runs. */
.special-days-overlay.vc-login.is-boot {
    animation: none;
}

/* Boot cover: until the startup check has mounted this screen, nothing of
   the calendar may be painted. visibility (not display) - app.js measures
   the calendar's layout. The class is set by a head script in index.html and
   always removed by auth/auth-startup-prompt.js (finally). */
html.vc-boot-login .app > :not(.vc-login) {
    visibility: hidden;
}

.special-days-overlay.vc-login.is-leaving {
    animation: vc-login-out 0.38s ease forwards;
    pointer-events: none;
}

.vc-login :focus-visible {
    outline: 2px solid var(--vc-gold);
    outline-offset: 2px;
}

/* Myanmar script: letter-spacing pulls stacked glyph clusters apart */
.vc-login[lang="my"] * {
    letter-spacing: 0 !important;
    text-transform: none !important;
    font-style: normal !important;
}


/* ---------------------------------------------------------------------
   Step 1 - the cinematic background. All layers live in ONE group,
   .vc-login-bg, stacked back to front:

     base     deep navy / indigo night sky with a warm gold "sun" behind the
              emblem and soft cool / violet light pools
     galaxy   a Milky Way haze (+ a fainter cool one) drifting at a
              medium-slow pace, and stars in three depths: far (slow sway),
              mid (moderate drift), a few near ones (the quickest, rising
              flow), some of them twinkling - all kept off the emblem disc
              so the KBS badge stays the focus
     ambient  two large soft blue lights that wander slowly - cool light
              against the warm gold gives the scene its depth
     beams    three soft, slanted shafts of gold light from above; they
              sway slowly and breathe (the volumetric light)
     rays     fine sunburst rays that turn slowly behind the emblem
     glow     a warm halo, concentric with the emblem
     motes    golden dust, far tier (behind the emblem)
     orbit    faint gold specks circling just outside the ring (~100 s a turn)
     orbitring a thin dashed gold ring, ONE svg concentric with the badge,
              turning slowly (90 s a turn) - the only thing in the scene
              that turns around the badge
     emblem   the KBS badge - exactly centred, standing still
     stars    a few sparse near stars (in front of the rays, behind the badge)
     motes    golden dust, mid + near tiers (in front of the emblem)
     veil     a light readability veil (kept thin so the scene stays bright)

   CAMERA  The intro is one slow push-in of the BACKGROUND: every layer
   sits in a "dolly" that eases from a slightly smaller scale to 1 over 7s,
   each from its own scale (--vc-push) - far layers barely move, near ones
   travel most: that difference is the parallax of a real camera. The badge,
   the orbit and the login card are not part of it: they only fade in.

   THE BADGE STANDS STILL  No sway, no tilt, no pointer parallax, no light
   sweep: the login card sits on its exact centre. The rotating gold ring
   is the only decoration that circles it.

   SCENE GEOMETRY  --vc-emblem (badge diameter) is defined once on the
   overlay and used by the badge, the orbit, the rays, the halo AND the login
   card, which is centred on the badge and sized as a fraction of it (see
   .vc-login-card).

   CENTRING  Every layer is a full-bleed box; the emblem is centred by
   its layer's grid, and the layers wider than the frame (rays, glow,
   blobs) by left/top 50% + negative margins - so all of them sit on the
   TRUE centre of the screen / phone frame at any size. Rotations and
   translateZ act around the emblem's own centre, which is the frame's
   centre, so the badge never drifts while it moves. The emblem is sized
   from the frame itself (container units), so the whole circle - ring
   included - stays visible however the frame is shaped.

   DEPTH     Each layer reads its own --vc-depth and shifts by that much
   with the pointer (desktop only; JS sets --vc-px / --vc-py) - far layers
   move less, near layers more.

   Everything animates with transform / opacity ONLY. The un-animated
   state of every layer is its finished look, so with reduced motion (or
   skipped) the scene is complete and still.
   --------------------------------------------------------------------- */

.vc-login-bg {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;

    /* (--vc-emblem, the badge diameter, comes from the overlay - see
       "scene geometry" there) */
    --vc-blob: 92%;
    container-type: size;

    animation: vc-login-fade-in 2.4s ease-out both;
}

@supports (width: 1cqw) {

    .vc-login-bg {
        --vc-blob: min(96cqw, 64cqh);
    }
}

/* one full-bleed, dead-centre grid per depth layer */
.vc-login-layer {
    position: absolute;
    inset: 0;

    display: grid;
    place-items: center;

    transform: translate3d(
        calc(var(--vc-px, 0) * var(--vc-depth, 0) * 1px),
        calc(var(--vc-py, 0) * var(--vc-depth, 0) * 0.7px),
        0);
    transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

/* the camera dolly of a layer: eases from --vc-push up to 1 (a slow push
   in) while the layer fades in (--vc-fade / --vc-fade-delay) */
.vc-login-dolly {
    position: absolute;
    inset: 0;

    animation:
        vc-login-dolly 7s cubic-bezier(0.26, 0.04, 0.12, 1) both,
        vc-login-fade-in var(--vc-fade, 2.4s) ease-out var(--vc-fade-delay, 0s) both;
}

.vc-login-layer--base    .vc-login-dolly { --vc-push: 0.94; animation-name: vc-login-dolly; }
.vc-login-layer--ambient .vc-login-dolly { --vc-push: 0.95; --vc-fade: 2.8s; --vc-fade-delay: 0.2s; }
.vc-login-layer--beams   .vc-login-dolly { --vc-push: 0.90; --vc-fade: 3.2s; --vc-fade-delay: 0.9s; }
.vc-login-layer--rays    .vc-login-dolly { --vc-push: 0.82; --vc-fade: 3s;   --vc-fade-delay: 0.4s; }
.vc-login-layer--glow    .vc-login-dolly { --vc-push: 0.74; --vc-fade: 2.4s; --vc-fade-delay: 0.2s; }
.vc-login-layer--far     .vc-login-dolly { --vc-push: 0.96; --vc-fade: 2.6s; --vc-fade-delay: 0.6s; }
.vc-login-layer--mid     .vc-login-dolly { --vc-push: 0.90; --vc-fade: 2.6s; --vc-fade-delay: 0.6s; }
.vc-login-layer--near    .vc-login-dolly { --vc-push: 0.80; --vc-fade: 2.6s; --vc-fade-delay: 0.6s; }

/* the galaxy: far layers barely move in the push-in, near ones travel most
   (they need no fade of their own: the whole background fades in) */
.vc-login-layer--milky      .vc-login-dolly { --vc-push: 0.96; animation-name: vc-login-dolly; }
.vc-login-layer--cirrus     .vc-login-dolly { --vc-push: 0.95; animation-name: vc-login-dolly; }
.vc-login-layer--stars-far  .vc-login-dolly { --vc-push: 0.97; animation-name: vc-login-dolly; }
.vc-login-layer--stars-mid  .vc-login-dolly { --vc-push: 0.94; animation-name: vc-login-dolly; }
.vc-login-layer--twinkle    .vc-login-dolly { --vc-push: 0.93; animation-name: vc-login-dolly; }
.vc-login-layer--stars-near .vc-login-dolly { --vc-push: 0.84; animation-name: vc-login-dolly; }
.vc-login-layer--orbit      .vc-login-dolly { --vc-push: 0.80; --vc-fade: 3s; --vc-fade-delay: 0.8s; }

/* the emblem layer and the orbit layer only fade in (the badge itself then
   stands perfectly still). The badge is deliberately NOT blended with the
   layers behind it: "screen" added the golden glow, base light and beams on
   top of the medallion and washed its navy out to grey-blue. */
.vc-login-layer--emblem {
    animation: vc-login-fade-in 1.1s ease-out 0.5s both;
}

.vc-login-layer--orbitring {
    animation: vc-login-fade-in 1.2s ease-out 0.8s both;
}

/* light that "breathes" - the rays and the beams swell and ebb slowly */
.vc-login-layer--rays  { animation: vc-login-breathe 13s ease-in-out infinite alternate; }
.vc-login-layer--beams { animation: vc-login-breathe 17s ease-in-out infinite alternate; }
.vc-login-layer--orbit { animation: vc-login-breathe 6s ease-in-out infinite alternate; }

/* the haze itself slowly swells and ebbs */
.vc-login-layer--milky  { animation: vc-login-breathe 16s ease-in-out infinite alternate; }
.vc-login-layer--cirrus { animation: vc-login-breathe 22s ease-in-out infinite alternate; }

.vc-login-bg-base {
    position: absolute;
    inset: -8%;                        /* bleed, so the slow drift never shows an edge */

    background:
        radial-gradient(72% 46% at 50% 47%, rgba(242, 202, 124, 0.18) 0%, rgba(242, 202, 124, 0) 70%),
        radial-gradient(92% 56% at 12% 6%, rgba(70, 108, 200, 0.09) 0%, rgba(70, 108, 200, 0) 62%),
        radial-gradient(92% 60% at 92% 96%, rgba(104, 82, 178, 0.09) 0%, rgba(104, 82, 178, 0) 64%),
        linear-gradient(180deg, var(--vc-scene-top) 0%, var(--vc-scene-mid) 46%, var(--vc-scene-low) 100%);

    animation: vc-login-drift 26s ease-in-out infinite alternate;
}

/* gentle blue ambient light: two big soft blobs on slow, different orbits
   (smaller than the frame, so a plain left/top 50% centres them) */
.vc-login-blob {
    position: absolute;
    left: 50%;
    top: 50%;
    width: var(--vc-blob);
    margin: calc(var(--vc-blob) * -0.5) 0 0 calc(var(--vc-blob) * -0.5);
    aspect-ratio: 1 / 1;
    border-radius: 50%;
}

.vc-login-blob--a {
    background: radial-gradient(circle closest-side,
        rgba(84, 132, 226, 0.13) 0%,
        rgba(84, 132, 226, 0.055) 48%,
        rgba(92, 148, 240, 0) 100%);
    transform: translate3d(-20%, -27%, 0);
    animation: vc-login-wander-a 21s ease-in-out infinite alternate;
}

.vc-login-blob--b {
    background: radial-gradient(circle closest-side,
        rgba(104, 96, 214, 0.11) 0%,
        rgba(104, 96, 214, 0.045) 48%,
        rgba(112, 104, 226, 0) 100%);
    transform: translate3d(19%, 29%, 0);
    animation: vc-login-wander-b 27s ease-in-out infinite alternate;
}

/* volumetric light: slanted shafts from above the frame. The gradient is
   an ellipse centred on the top edge, so each shaft is brightest at its
   source and fades with distance in both directions - no mask needed.
   Position / angle / strength come from the JS (--x --w --r --a --t --d). */
.vc-login-beam {
    position: absolute;
    top: -10%;
    left: var(--x);
    width: var(--w);
    height: 96%;
    margin-left: calc(var(--w) / -2);

    transform-origin: 50% 0;
    transform: rotate(var(--r));

    background: radial-gradient(ellipse 50% 100% at 50% 0%,
        rgba(255, 228, 168, var(--a)) 0%,
        rgba(255, 228, 168, calc(var(--a) * 0.42)) 46%,
        rgba(255, 228, 168, 0) 100%);

    animation: vc-login-beam var(--t) ease-in-out var(--d) infinite alternate;
}

.vc-login-rays {
    /* wider than the frame, so it is centred with left/top 50% + a negative
       margin (half its own size): a grid item that overflows its area is
       start-aligned by the browser and would end up off-centre */
    position: absolute;
    left: 50%;
    top: 50%;
    width: calc(var(--vc-emblem) * 2.3);
    margin: calc(var(--vc-emblem) * -1.15) 0 0 calc(var(--vc-emblem) * -1.15);
    aspect-ratio: 1 / 1;
    border-radius: 50%;

    background: repeating-conic-gradient(from 8deg,
        rgba(246, 218, 150, 0.16) 0deg 2.6deg,
        rgba(246, 218, 150, 0) 2.6deg 15deg);

    /* fade the rays in from behind the badge and out to nothing */
    -webkit-mask-image: radial-gradient(circle closest-side, transparent 30%, #000 43%, rgba(0, 0, 0, 0.5) 68%, transparent 100%);
            mask-image: radial-gradient(circle closest-side, transparent 30%, #000 43%, rgba(0, 0, 0, 0.5) 68%, transparent 100%);

    animation: vc-login-spin 120s linear infinite;
    will-change: transform;
}

/* a finer, counter-turning set - the two sets sliding over each other is
   what gives the rays their depth */
.vc-login-rays::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;

    background: repeating-conic-gradient(from 0deg,
        rgba(196, 222, 255, 0.07) 0deg 1.4deg,
        rgba(196, 222, 255, 0) 1.4deg 9deg);

    animation: vc-login-spin 170s linear infinite reverse;
}

.vc-login-glow {
    position: absolute;      /* centred like the rays - it is wider than the frame too */
    left: 50%;
    top: 50%;
    width: calc(var(--vc-emblem) * 1.5);
    margin: calc(var(--vc-emblem) * -0.75) 0 0 calc(var(--vc-emblem) * -0.75);
    aspect-ratio: 1 / 1;
    border-radius: 50%;

    /* the box is 1.5x the badge, so the badge's edge is at 66.7%: the
       badge covers the inside, and what shows is a soft gold halo that
       fades out from its edge */
    background: radial-gradient(circle closest-side,
        rgba(248, 210, 132, 0.30) 0%,
        rgba(248, 210, 132, 0.24) 64%,
        rgba(226, 190, 112, 0.11) 73%,
        rgba(214, 178, 110, 0) 92%);

    animation: vc-login-glow 8s ease-in-out infinite;
}

/* -- the emblem: the KBS badge, standing still ---------------------- */

.vc-login-emblem {
    position: relative;
    width: var(--vc-emblem);
    aspect-ratio: 1 / 1;

    /* the only movement: it settles in with a small rise as it fades in */
    animation: vc-login-emblem-in 1.2s cubic-bezier(0.22, 1, 0.36, 1) 0.5s both;
}

.vc-login-medal,
.vc-login-swing,
.vc-login-tilt {
    position: absolute;
    inset: 0;
}

.vc-login-logo {
    /* both copies (sharp + soft) lie exactly on top of each other */
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    max-width: none;

    object-fit: cover;
    border-radius: 50%;

    /* only the very rim is feathered, so the medallion stays crisp */
    -webkit-mask-image: radial-gradient(circle closest-side, #000 93%, transparent 100%);
            mask-image: radial-gradient(circle closest-side, #000 93%, transparent 100%);

    user-select: none;
    -webkit-user-drag: none;

    /* The badge is two copies of the same image, so the change between the
       intro and the resting look needs nothing but opacity: the SHARP copy
       is the intro look (full strength) and fades out as the login card
       arrives; the SOFT copy is the resting look, only a little quieter,
       behind the card. The soft copy comes in FIRST and the sharp one fades
       out over it, so the badge never dips dim in between. This rule is the
       sharp copy; at rest it is invisible. */
    opacity: 0;
    animation: vc-login-logo-sharp 1.2s ease 2.4s both;
}

.vc-login-logo--soft {
    opacity: 0.85;
    animation: vc-login-logo-soft 0.5s ease 2.3s both;
}

/* -- the golden orbit ring ------------------------------------------------
   ONE svg (built by the JS; the badge radius = 100 units, the svg spans 240),
   1.2x the badge and concentric with it. It is the only thing that turns:
   one slow, linear, endless rotation - a full 360deg loop, so nothing jumps
   or resets at the end of a turn. */
.vc-login-orbitring,
.vc-login-mantra {
    position: absolute;          /* centred like the rays: left/top 50% + negative margin */
    left: 50%;
    top: 50%;
    width: calc(var(--vc-emblem) * 1.2);
    height: calc(var(--vc-emblem) * 1.2);
    margin: calc(var(--vc-emblem) * -0.6) 0 0 calc(var(--vc-emblem) * -0.6);
    overflow: visible;

    animation: vc-login-spin 90s linear infinite;
    will-change: transform;
}

/* the Maha Mantra ring: same box, same clockwise direction, slower (120 s).
   Three full repetitions of the mantra share the ring's circumference, so
   the font-size is reduced (was 6px for one repetition) to where the
   text's own natural width already lands almost exactly on the
   circumference at default letter-spacing (measured) - the JS's
   textLength/lengthAdjust="spacing" then only needs a hair of adjustment
   to close the loop exactly, instead of visibly stretching or squeezing
   the letters. */
.vc-login-mantra {
    animation-duration: 120s;

    font: 400 4.6px Georgia, "Times New Roman", serif;
    fill: rgba(232, 212, 160, 0.95);
}

/* golden dust in three depths (created by the JS): far motes are small,
   dim and slow; near ones large, soft and quicker. Each mote is ONE element
   - a soft disc that follows one path + fade (see the keyframes). */
.vc-login-mote {
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: var(--s);
    height: var(--s);
    margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
    border-radius: 50%;

    background: radial-gradient(circle,
        rgba(255, 238, 196, 0.95) 0%,
        rgba(255, 226, 160, 0.5) 40%,
        rgba(255, 226, 160, 0) 72%);

    opacity: 0;
    animation:
        vc-login-mote-path var(--t) linear var(--d) infinite,
        vc-login-mote-fade var(--t) ease-in-out var(--d) infinite;
}

.vc-login-layer--near .vc-login-mote {
    background: radial-gradient(circle,
        rgba(255, 236, 190, 0.6) 0%,
        rgba(255, 226, 160, 0.3) 48%,
        rgba(255, 226, 160, 0) 74%);
}

/* -- the galaxy: Milky Way haze, stars, golden dust ------------------
   The two haze canvases are painted once by the JS (a few hundred px
   wide, ~60 KB of texture) and stretched over the frame by CSS: soft
   cloud, tiny memory. Everything moves on transform / opacity only. */

/* the Milky Way band: slanted (about -58deg, bottom-left to top-right),
   long enough to cross the whole frame, drifting very slowly along and
   across itself. The base rotation is repeated in the keyframes. */
.vc-login-milky {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 240%;                /* fallbacks for browsers without container units */
    height: 30%;

    transform: translate(-50%, -50%) rotate(-58deg);
    opacity: 0.85;

    animation: vc-login-milky-drift 38s ease-in-out infinite alternate;
}

/* a second, cooler and fainter haze, drifting the other way */
.vc-login-cirrus {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 120%;
    height: 56%;

    transform: translate(-50%, -50%) translate3d(26%, -34%, 0);
    opacity: 0.8;

    animation: vc-login-cirrus-drift 46s ease-in-out infinite alternate;
}

@supports (width: 1cqw) {

    .vc-login-milky {
        width: 122cqh;          /* along the band: a little more than the frame diagonal */
        height: 33cqh;
    }

    .vc-login-cirrus {
        width: min(120cqw, 84cqh);
        height: min(120cqw, 84cqh);
    }
}

/* star fields: ONE element each, every star a tiny gradient. Far stars
   sway a little, mid stars drift further and quicker. Oversized a little
   (inset -5%) so the drift never shows an edge. */
.vc-login-starfield {
    position: absolute;
    inset: -5%;
}

.vc-login-starfield--far {
    animation: vc-login-star-drift-far 26s ease-in-out infinite alternate;
}

.vc-login-starfield--mid {
    animation: vc-login-star-drift 16s ease-in-out infinite alternate;
}

/* a star (created by the JS): a static soft dot. Twinkling is done per
   CLUSTER (below), not per star - animating a dozen separate elements
   costs the frame rate on a phone, four clusters do not. */
.vc-login-star {
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: var(--s);
    height: var(--s);
    margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
    border-radius: 50%;

    background: radial-gradient(circle,
        rgba(var(--c), 1) 0%,
        rgba(var(--c), 0.5) 38%,
        rgba(var(--c), 0) 72%);

    opacity: var(--a);
}

/* a cluster of three stars that glimmers together: opacity only, never
   down to nothing (25%), so it shimmers rather than flashes. The four
   clusters have different rhythms and phases (2.4 - 5.6 s per fade). */
.vc-login-twinkle {
    position: absolute;             /* left / top / width / height come from the JS */
    animation: vc-login-twinkle var(--t) ease-in-out var(--d) infinite alternate;
}

/* the few near stars: a little larger and softer, and the quickest layer:
   each one drifts up on a lazy S-curve and fades in and out, exactly like
   the golden motes (same keyframes), so the flow never reverses */
.vc-login-star--near {
    background: radial-gradient(circle,
        rgba(var(--c), 0.85) 0%,
        rgba(var(--c), 0.34) 45%,
        rgba(var(--c), 0) 74%);

    animation:
        vc-login-mote-path var(--t) linear var(--d) infinite,
        vc-login-mote-fade var(--t) ease-in-out var(--d) infinite;
}

/* very subtle golden dust in a slow orbit just outside the gold ring
   (sized from the emblem, centred like the rays) */
.vc-login-orbit {
    position: absolute;
    left: 50%;
    top: 50%;
    width: calc(var(--vc-emblem) * 1.36);
    margin: calc(var(--vc-emblem) * -0.68) 0 0 calc(var(--vc-emblem) * -0.68);
    aspect-ratio: 1 / 1;

    animation: vc-login-spin 100s linear infinite;
}

.vc-login-veil {
    position: absolute;
    inset: 0;

    /* thin on purpose: enough to hold the text, not enough to dull the scene */
    background:
        radial-gradient(ellipse 96% 76% at 50% 46%, rgba(5, 8, 16, 0) 46%, rgba(5, 8, 16, 0.34) 100%),
        linear-gradient(180deg,
            rgba(5, 8, 16, 0.34) 0%,
            rgba(5, 8, 16, 0.06) 34%,
            rgba(5, 8, 16, 0.10) 60%,
            rgba(5, 8, 16, 0.50) 100%);
}


/* ---------------------------------------------------------------------
   Stage - the greeting above the badge, the login card ON the badge
   --------------------------------------------------------------------- */

/* The stage is the same box as the background, and the card is centred in
   it: that is the centre of the badge (and of the orbit). The stage itself
   never scrolls - the card scrolls inside itself if it is ever taller than
   the frame (Create Account on a very small phone). */
.vc-login-stage {
    position: absolute;
    inset: 0;
    z-index: 1;

    display: grid;
    place-items: center;

    overflow: hidden;
}

/* the greeting: centred between the top of the frame and the orbit (sized
   for the orbit's original outer edge), so the space above the greeting and
   the space between the credit line and the orbit are equal */
.vc-login-hero {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: calc(50cqh - var(--vc-emblem) * 0.566);
    box-sizing: border-box;
    padding: env(safe-area-inset-top, 0px) 16px 0;

    isolation: isolate;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;

    text-align: center;
}

/* a soft dark scrim behind the greeting keeps it readable over the rays */
.vc-login-hero::before {
    content: "";
    position: absolute;
    inset: 4% -8% 0;
    z-index: -1;
    pointer-events: none;

    /* closest-side: the gradient reaches 0 exactly at the box edges, so the
       scrim never leaves a visible horizontal / vertical edge */
    background: radial-gradient(ellipse closest-side at 50% 50%,
        rgba(4, 8, 18, 0.62) 0%,
        rgba(4, 8, 18, 0.5) 34%,
        rgba(4, 8, 18, 0.26) 66%,
        rgba(4, 8, 18, 0) 100%);

    animation: vc-login-fade-in 1.2s ease 1.2s both;
}

/* step 3: "Hare Krishna" - the sizes follow the frame height (cqh), so the
   greeting always fits above the badge, from 320x568 up to a tall desktop
   frame */
.vc-login-hare {
    margin: 0;

    font: italic 400 32px/1.15 Georgia, "Times New Roman", serif;
    font-size: clamp(27px, 4.3cqh, 36px);
    letter-spacing: 0.04em;

    background: linear-gradient(180deg, #f8e6b3 0%, var(--vc-gold) 55%, var(--vc-gold-lo) 100%);
    -webkit-background-clip: text;
            background-clip: text;
    color: transparent;

    /* a clearly visible but soft warm-gold glow (letters stay sharp: drop-shadow
       glows the alpha silhouette behind the crisp text, it never blurs the text itself) */
    filter: drop-shadow(0 0 10px rgba(240, 205, 140, 0.65)) drop-shadow(0 0 22px rgba(230, 190, 120, 0.4));
}

.vc-login-welcome {
    margin: 0;

    font-size: 12px;
    font-size: clamp(10.5px, 1.5cqh, 12.5px);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.36em;
    text-transform: uppercase;

    color: var(--vc-muted);
}

/* The title is ONE line at every size: nowrap + a font size that follows
   the frame WIDTH (cqw; the string is ~14.8 em wide, and the hero keeps 16px
   of padding on each side) and, like the greeting above it, the frame
   height (cqh) - whichever is smaller. */
.vc-login-title {
    max-width: 100%;
    margin: 2px 0 0;

    font: 400 22px/1.28 Georgia, "Times New Roman", serif;
    font-size: min(clamp(18px, 2.95cqh, 25px), calc((100cqw - 32px) / 14.8));
    letter-spacing: 0.01em;
    white-space: nowrap;

    color: var(--vc-cream);
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.65);
}

/* the credit line, directly under the title: one centred line, clearly
   smaller than the title, in a quiet warm ivory-gold. Its size follows the
   frame width too (45 characters must fit between the hero's paddings). */
.vc-login-subtitle {
    max-width: 100%;
    margin: 1px 0 0;

    font-size: 11px;
    font-size: clamp(9.5px, calc((100cqw - 32px) / 26), 13px);
    line-height: 1.35;
    letter-spacing: 0.02em;
    white-space: nowrap;

    color: rgba(236, 216, 168, 0.9);
}


/* ---------------------------------------------------------------------
   The login card - Midnight Navy glass, centred ON the badge
   --------------------------------------------------------------------- */

.vc-login-card {
    position: relative;
    box-sizing: border-box;

    /* --vc-card-scale enlarges the card AND (via --vc-u, which the whole
       card's contents are built from - padding, gaps, fonts, input/button
       heights, links) everything inside it, by the same factor, so nothing
       grows out of proportion. 1.07: the corner math below still lands
       comfortably inside the badge's own circular edge (never mind the
       printed inner gold rim), with clear room to spare before the mantra
       ring starts (~101.6% of the badge radius). */
    --vc-card-scale: 1.07;

    /* 1% of the badge diameter, scaled: every size inside the card is a
       multiple of it, so the whole card (and its contents) scales with the
       badge - and with --vc-card-scale. */
    --vc-u: calc(var(--vc-emblem) / 100 * var(--vc-card-scale));

    /* A compact rounded rectangle, centred on the badge (the stage is the
       badge's own box) and sized as a fraction of it, scaled up by
       --vc-card-scale:
           width 0.59 - height 0.70 - corner radius 0.06 (x badge diameter)
       The four equal corner arcs reach at most
           (hypot(0.59/2 - 0.06, 0.70/2 - 0.06) + 0.06) * scale
           = 0.433 * scale of the diameter = 0.866 * scale of the badge
       radius - at scale 1.07, 0.927 of the badge radius: safely inside the
       badge's own circular edge (1.0) and the mantra ring (~1.016) beyond
       it, at every screen size, because everything is a fraction of
       --vc-emblem. The height is a MINIMUM: longer content (Create
       Account, a message) grows the card evenly around the same centre. */
    width: calc(var(--vc-emblem) * 0.59 * var(--vc-card-scale));
    min-height: calc(var(--vc-emblem) * 0.70 * var(--vc-card-scale));
    max-height: calc(100cqh - 20px);
    margin: auto;
    padding: calc(var(--vc-u) * 2.8) calc(var(--vc-u) * 3.4);

    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: calc(var(--vc-u) * 1.5);

    border-radius: calc(var(--vc-emblem) * 0.06 * var(--vc-card-scale));
    border: 1px solid rgba(216, 182, 106, 0.7);

    /* Midnight Navy glass: ~95% opaque #071B38 with only a faint highlight
       along the upper left - the form area never turns muddy */
    background:
        linear-gradient(158deg, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0) 34%),
        rgba(7, 27, 56, 0.95);
    -webkit-backdrop-filter: blur(10px) saturate(1.15);
            backdrop-filter: blur(10px) saturate(1.15);

    box-shadow:
        0 16px 38px rgba(0, 0, 0, 0.5),
        inset 0 1px 0 rgba(255, 255, 255, 0.09);

    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: rgba(214, 178, 110, 0.4) transparent;
}


/* ---------------------------------------------------------------------
   The controls (Email / Password / Login, Forgot, Create account)
   Every size is a multiple of --vc-u (1% of the badge diameter, defined on
   the card) with a floor, so the form stays compact inside the card. Inputs
   keep font-size 16px: anything smaller makes iOS zoom the page on focus.
   --------------------------------------------------------------------- */

.vc-login-creds {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;

    display: flex;
    flex-direction: column;
    gap: calc(var(--vc-u) * 1.6);
}

.vc-login-field {
    display: flex;
    flex-direction: column;
    gap: calc(var(--vc-u) * 0.5);
}

.vc-login-label {
    font-size: 10px;
    font-size: clamp(9px, calc(var(--vc-u) * 2.7), 11px);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.08em;
    text-transform: uppercase;

    color: var(--vc-muted);
}

.vc-login-input {
    width: 100%;
    height: 32px;
    height: max(26px, calc(var(--vc-u) * 8.6));
    box-sizing: border-box;
    padding: 0 calc(var(--vc-u) * 3);

    /* a slightly lighter navy than the card, with a soft blue border */
    border-radius: 9px;
    border-radius: calc(var(--vc-u) * 2.4);
    border: 1px solid rgba(120, 156, 226, 0.4);
    background: #15365b;

    /* 16px: stops iOS from zooming the page on focus */
    font-size: 16px;
    color: var(--vc-text);

    outline: none;
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}

.vc-login-input::placeholder {
    color: rgba(244, 246, 248, 0.42);

    /* the typed text stays 16px (iOS zoom); only the hint is a little
       smaller, so "name@example.com" fits the compact field */
    font-size: 14px;
}

.vc-login-input:focus {
    border-color: var(--vc-gold);
    background: #1b3f6b;
    box-shadow: 0 0 0 2px rgba(214, 178, 110, 0.26);
}

/* gold primary button - Login / Create Account, and Send Code / Verify */
.vc-login-primary {
    width: 100%;
    min-height: 32px;
    min-height: max(28px, calc(var(--vc-u) * 9));
    padding: 0 12px;

    border: none;
    border-radius: 9px;
    border-radius: calc(var(--vc-u) * 2.4);

    background: linear-gradient(180deg, var(--vc-gold-hi) 0%, var(--vc-gold) 58%, var(--vc-gold-lo) 100%);
    box-shadow: 0 4px 14px rgba(214, 178, 110, 0.26);

    font-size: 14px;
    font-size: clamp(12.5px, calc(var(--vc-u) * 3.7), 15px);
    font-weight: 700;
    letter-spacing: 0.04em;
    color: #1a1408;

    cursor: pointer;
    transition: transform 0.15s ease, filter 0.2s ease;
}

.vc-login-primary:hover:not(:disabled) {
    filter: brightness(1.06);
}

.vc-login-primary:active:not(:disabled) {
    transform: scale(0.985);
}

/* the credentials form wraps the fieldset; it adds no box of its own */
.vc-login-credform {
    margin: 0;
    min-width: 0;
}

/* .vc-login-field sets display:flex, which would beat the hidden attribute */
.vc-login-field[hidden] {
    display: none;
}

/* Username + Confirm Password only exist in "create account" mode: they fade
   in when you switch (like the phone panel), instead of joining the intro
   reveal */
.vc-login-field--register {
    animation: vc-login-panel-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* username rules, shown under the field in "create account" mode */
.vc-login-hint {
    margin: 0;

    font-size: 10px;
    font-size: clamp(9.5px, calc(var(--vc-u) * 2.7), 11px);
    line-height: 1.35;

    color: var(--vc-muted);
}

.vc-login-hint[hidden] {
    display: none;
}

/* Login <-> Create account - the row that replaced the "Coming soon" note;
   "Forgot Password?" (login mode only) is the same kind of link */
.vc-login-switch,
.vc-login-forgot,
.vc-login-resend {
    text-align: center;
    line-height: 1.3;
}

/* .vc-login-link sets its own display, which would beat the hidden attribute */
.vc-login-switch[hidden],
.vc-login-forgot[hidden],
.vc-login-resend[hidden] {
    display: none;
}

/* options hidden on the verification screen (they set their own display) */
.vc-login-google[hidden],
.vc-login-phone-toggle[hidden] {
    display: none;
}

/* "Verify your email" heading (verification screen only) */
.vc-login-verify-title {
    margin: 0;

    text-align: center;
    font-size: 15px;
    font-size: clamp(13px, calc(var(--vc-u) * 4), 16px);
    font-weight: 700;
    letter-spacing: 0.02em;

    color: var(--vc-gold);
}

.vc-login-verify-title[hidden] {
    display: none;
}


/* ---------------------------------------------------------------------
   Google Account / Or Phone Number
   --------------------------------------------------------------------- */

/* the gold diamond divider (a line fading out to both sides) is a gold
   flourish: this design has none in the card. The element stays in the
   markup (the JS toggles it with the Google button) but is not displayed. */
.vc-login-divider {
    display: none;
}

.vc-login-google,
.vc-login-phone-toggle {
    width: 100%;
    min-height: 32px;
    min-height: max(28px, calc(var(--vc-u) * 9));
    padding: 0 12px;

    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;

    border-radius: 9px;
    border-radius: calc(var(--vc-u) * 2.4);

    font-size: 13px;
    font-size: clamp(11.5px, calc(var(--vc-u) * 3.5), 14px);
    font-weight: 700;

    cursor: pointer;
    transition: transform 0.15s ease, filter 0.2s ease, background 0.2s ease;
}

.vc-login-google {
    border: none;
    background: #f8f5ec;
    color: #1f2937;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.32);
}

.vc-login-google:hover {
    filter: brightness(1.04);
}

.vc-login-google svg {
    width: 16px;
    height: 16px;
    flex: none;
}

.vc-login-phone-toggle {
    border: 1px solid rgba(214, 178, 110, 0.55);
    background: rgba(214, 178, 110, 0.09);
    color: var(--vc-cream);
}

.vc-login-phone-toggle:hover {
    background: rgba(214, 178, 110, 0.16);
}

.vc-login-phone-toggle[aria-expanded="true"] {
    background: rgba(214, 178, 110, 0.18);
}

.vc-login-phone-toggle svg {
    width: 16px;
    height: 16px;
    flex: none;

    fill: none;
    stroke: var(--vc-gold);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.vc-login-google:active,
.vc-login-phone-toggle:active {
    transform: scale(0.985);
}

.vc-login button[aria-busy="true"] {
    opacity: 0.65;
    pointer-events: none;
}


/* inline phone-number panel (opens under "Or Phone Number") */

.vc-login-phone {
    display: flex;
    flex-direction: column;
    gap: 12px;

    /* opacity/transform only (no visibility): its first field is focused
       the moment the panel opens, and a visibility:hidden element cannot
       take focus */
    animation: vc-login-panel-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.vc-login-phone-info {
    margin: 0;

    font-size: 13px;
    line-height: 1.5;
    text-align: center;

    color: var(--vc-muted);
}

/* text links (Forgot Password? / Create an account / Resend). Compact to
   the eye; the ::after grows the tap area without taking any room. */
.vc-login-link {
    position: relative;
    align-self: center;
    min-height: 0;
    padding: 4px 0;
    margin: -2px 0;

    border: none;
    background: none;

    font-size: 12px;
    font-size: clamp(9.5px, calc(var(--vc-u) * 3.1), 12.5px);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;

    color: var(--vc-gold);
    cursor: pointer;
}

.vc-login-link::after {
    content: "";
    position: absolute;
    inset: -7px -10px;
}

/* .vc-login-error = the card's shared message (Google / Phone);
   .vc-login-cred-error = the message under the Email / Password form */
.vc-login-error,
.vc-login-cred-error {
    margin: 0;
    padding: 6px 8px;

    border-radius: 8px;
    border: 1px solid rgba(255, 120, 120, 0.4);
    background: rgba(214, 70, 70, 0.14);

    font-size: 11px;
    font-size: clamp(10px, calc(var(--vc-u) * 3), 12px);
    line-height: 1.35;

    color: #ffd6d6;
}

.vc-login-error[hidden],
.vc-login-cred-error[hidden] {
    display: none;
}

/* a confirmation, not an error: password-reset mail sent / account created */
.vc-login-cred-note {
    margin: 0;
    padding: 6px 8px;

    border-radius: 8px;
    border: 1px solid rgba(214, 178, 110, 0.45);
    background: rgba(214, 178, 110, 0.12);

    font-size: 11px;
    font-size: clamp(10px, calc(var(--vc-u) * 3), 12px);
    line-height: 1.35;

    color: #f3e2b8;
}

.vc-login-cred-note[hidden] {
    display: none;
}

/* a long unbroken word - typically an email address in the verification
   message - wraps inside the box instead of running past its edge */
.vc-login-error,
.vc-login-cred-error,
.vc-login-cred-note {
    overflow-wrap: anywhere;
}

/* Create Account: "you agree to the Terms of Use and the Privacy Policy" */
.vc-login-legal {
    margin: 0;

    font-size: 10px;
    font-size: clamp(9px, calc(var(--vc-u) * 2.8), 11px);
    line-height: 1.35;
    text-align: center;

    color: var(--vc-muted);
}

.vc-login-legal[hidden] {
    display: none;
}

.vc-login-legal-link {
    color: var(--vc-gold-hi);
    text-decoration: underline;
    text-underline-offset: 2px;
}


/* guest link - keeps the whole calendar usable without an account */

.vc-login-guest {
    /* (only shown while GUEST_LOGIN_ENABLED) pinned under the scene, so it
       takes no part in centring the card */
    position: absolute;
    left: 0;
    right: 0;
    bottom: max(10px, env(safe-area-inset-bottom));
    width: max-content;
    margin: 0 auto;

    min-height: 40px;
    padding: 8px 18px;

    border: none;
    background: none;

    font-size: 14px;
    font-weight: 600;
    text-decoration: underline;
    text-decoration-color: rgba(214, 178, 110, 0.5);
    text-underline-offset: 5px;

    color: var(--vc-muted);
    cursor: pointer;
}

.vc-login-guest:hover {
    color: var(--vc-cream);
}

/* the scene behind is brighter now - a soft dark halo keeps the greeting
   and the guest link crisp against the badge */
.vc-login-welcome,
.vc-login-title,
.vc-login-subtitle,
.vc-login-guest {
    text-shadow: 0 1px 14px rgba(4, 8, 18, 0.9);
}

.vc-login-subtitle {
    text-shadow:
        0 0 2px rgba(4, 8, 18, 0.95),
        0 0 7px rgba(4, 8, 18, 0.85),
        0 1px 14px rgba(4, 8, 18, 0.9);
}


/* ---------------------------------------------------------------------
   Very narrow phones (320px): the badge is ~282px wide there (the mantra
   ring needs the rest of the width), so the control floors are one notch
   tighter to keep the card at its designed size (its corners stay inside
   the badge's gold rim).
   --------------------------------------------------------------------- */

@media (max-width: 340px) {

    /* these floors are nudged up by the same --vc-card-scale as the rest
       of the card, so the enlarged card's contents stay proportionally
       bigger here too, not pinned back to the pre-enlargement size */
    .vc-login-card {
        gap: 3.2px;
        padding-top: 6.4px;
        padding-bottom: 6.4px;
    }

    .vc-login-creds {
        gap: 3.2px;
    }

    .vc-login-field {
        gap: 1.1px;
    }

    .vc-login-input {
        height: 25.7px;
    }

    .vc-login-primary,
    .vc-login-google {
        min-height: 27.8px;
    }

    .vc-login-link {
        padding: 2.1px 0;
        margin: -1.1px 0;
    }
}


/* ---------------------------------------------------------------------
   Desktop phone-frame (>=600px)
   There .app is a rounded, overflow:hidden card whose height follows the
   calendar content (~760px on a festival day), NOT the browser window, so
   the login must be sized to the card rather than to the screen:
     - the overlay switches from "fixed to the screen" (phones) back to
       "exactly the card" (absolute inside .app, like Settings / sidebar),
     - while the login is open the card is given a phone-like height of its
       own (window height minus the 24px body padding top + bottom) - NOT
       the calendar's height, which changes from day to day (760px one day,
       1083px the next) and used to push the login below the window,
     - the stage (scroll container, defined above) fills the overlay and
       centres its content; if the content is still taller than the card
       (phone panel + error message open) it scrolls inside the card
       instead of being clipped. The background stays put.
   --------------------------------------------------------------------- */

@media (min-width: 600px) {

    .app:has(> .vc-login) {
        height: clamp(660px, calc(100vh - 48px), 960px);
        height: clamp(660px, calc(100dvh - 48px), 960px);
    }

    .special-days-overlay.vc-login {
        position: absolute;
        inset: 0;
    }
}


/* ---------------------------------------------------------------------
   Phones (<600px): GPU tile memory
   The Android WebView gives a page only ~20 screens of tile memory, and
   this scene needs more - the WebView then silently skips whole layers
   (the Maha Mantra ring was the one dropped). Two savings, both phone-only
   so the desktop phone-frame look is untouched:
     - the fine counter-turning rays set (a second rotating layer about
       2x the screen) is left out; the main gold rays stay,
     - the calendar under the opaque login is not painted while the login
       is open (it comes back as the login starts to fade out, so the
       fade still reveals it). Other overlays appended to .app are not
       affected.
   --------------------------------------------------------------------- */

@media (max-width: 599px) {

    .vc-login-rays::after {
        display: none;
    }

    /* the decorative haze (Milky Way band + cirrus) and the two blue
       blobs are left out: they sit under the stars / rays on the dark base
       and cost about 2.3 screens of tile area. Rays, stars, beams, veil and
       base stay. */
    .vc-login-layer--milky,
    .vc-login-layer--cirrus,
    .vc-login-layer--ambient {
        display: none;
    }

    .app:has(> .vc-login:not(.is-leaving)) > .app-header,
    .app:has(> .vc-login:not(.is-leaving)) > .side-menu,
    .app:has(> .vc-login:not(.is-leaving)) > .calendar-container {
        visibility: hidden;
    }

    /* no backdrop blur under the ~95% opaque login card: the blur barely
       shows, but it re-read and re-blurred the turning rays / ring / mantra
       under the card on every frame (desktop keeps it) */
    .vc-login-card {
        -webkit-backdrop-filter: none;
                backdrop-filter: none;
    }
}


/* ---------------------------------------------------------------------
   TIMELINE  -  when each step appears (single source of truth)
   --------------------------------------------------------------------- */

/* background 0s > badge + orbit 0.5s / 0.8s (set on their layers above) >
   greeting > card > the controls, one after another */
.vc-login [data-step="hare"]     { --vc-delay: 1.5s;  }
.vc-login [data-step="welcome"]  { --vc-delay: 1.8s;  }
.vc-login [data-step="title"]    { --vc-delay: 2.1s;  }
.vc-login [data-step="subtitle"] { --vc-delay: 2.4s;  }
.vc-login [data-step="card"]     { --vc-delay: 2.7s;  }
.vc-login [data-step="username"] { --vc-delay: 3.1s;  }
.vc-login [data-step="password"] { --vc-delay: 3.25s; }
.vc-login [data-step="login"]    { --vc-delay: 3.4s;  }
.vc-login [data-step="soon"]     { --vc-delay: 3.55s; }
.vc-login [data-step="google"]   { --vc-delay: 3.7s;  }
.vc-login [data-step="phone"]    { --vc-delay: 3.85s; }
.vc-login [data-step="guest"]    { --vc-delay: 4.0s;  }

/* Each step = two animations at the same delay: the eased fade / rise
   (opacity + transform only, so the compositor runs it - a "visibility" in
   those keyframes kept it on the main thread, re-rasterising the card every
   frame, and on the Android WebView the login card flickered as it came in)
   plus vc-login-reveal-vis, a 0s step that keeps the element
   visibility:hidden until its step starts. */
.vc-login .vc-reveal {
    animation:
        vc-login-rise 0.8s cubic-bezier(0.22, 1, 0.36, 1) var(--vc-delay, 0s) both,
        vc-login-reveal-vis 0s linear var(--vc-delay, 0s) both;
}

.vc-login .vc-login-hare.vc-reveal {
    animation-name: vc-login-hare-in, vc-login-reveal-vis;
    animation-duration: 1.1s, 0s;
}

.vc-login .vc-login-card.vc-reveal {
    animation-name: vc-login-card-in, vc-login-reveal-vis;
    animation-duration: 0.9s, 0s;
}


/* ---------------------------------------------------------------------
   Fast-forward (tap / key) and reduced motion
   --------------------------------------------------------------------- */

/* skipping fast-forwards the INTRO only (fades, the badge's arrival): those
   one-shot animations sit on their own elements (dolly / emblem layer /
   orbit layer / emblem), so the ambient loops - rays, beams, dust and the
   turning orbit itself - keep running and the scene stays alive. */
.special-days-overlay.vc-login.is-instant,
.vc-login.is-instant .vc-login-bg,
.vc-login.is-instant .vc-login-dolly,
.vc-login.is-instant .vc-login-layer--emblem,
.vc-login.is-instant .vc-login-layer--orbitring,
.vc-login.is-instant .vc-login-emblem,
.vc-login.is-instant .vc-login-logo,
.vc-login.is-instant .vc-login-hero::before,
.vc-login.is-instant .vc-reveal {
    animation: none;
}

@media (prefers-reduced-motion: reduce) {

    .special-days-overlay.vc-login,
    .vc-login-bg,
    .vc-login-layer,
    .vc-login-dolly,
    .vc-login-bg-base,
    .vc-login-blob,
    .vc-login-beam,
    .vc-login-rays,
    .vc-login-rays::after,
    .vc-login-glow,
    .vc-login-milky,
    .vc-login-cirrus,
    .vc-login-starfield,
    .vc-login-twinkle,
    .vc-login-star,
    .vc-login-orbit,
    .vc-login-orbitring,
    .vc-login-mantra,
    .vc-login-emblem,
    .vc-login-logo,
    .vc-login-hero::before,
    .vc-login .vc-reveal,
    .vc-login-field--register,
    .vc-login-phone {
        animation: none !important;
    }

    /* a still scene: no drifting dust, no pointer parallax - and the gold
       ring stands still too (animation: none above) */
    .vc-login-layer--motes,
    .vc-login-layer--orbit {
        display: none;
    }

    .vc-login-layer {
        transform: none !important;
        transition: none;
    }
}

/* ---------------------------------------------------------------------
   Keyframes
   --------------------------------------------------------------------- */

@keyframes vc-login-overlay-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes vc-login-out {
    from { opacity: 1; }
    to   { opacity: 0; }
}

/* the whole background (and, with their own timing, most layers) fades in */
@keyframes vc-login-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

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

/* the light pools of the base drift slowly, back and forth */
@keyframes vc-login-drift {
    from { transform: translate3d(-2.2%, -1.4%, 0) scale(1.03); }
    to   { transform: translate3d(2.2%, 1.4%, 0) scale(1.06); }
}

/* the camera push-in: a layer eases from its own smaller scale up to 1 */
@keyframes vc-login-dolly {
    from { transform: scale(var(--vc-push, 0.9)); }
    to   { transform: none; }
}

/* light that swells and ebbs (rays, beams) */
@keyframes vc-login-breathe {
    from { opacity: 1; }
    to   { opacity: 0.62; }
}

/* ambient loops (very subtle) */
@keyframes vc-login-glow {
    0%   { opacity: 1;    transform: scale(1); }
    50%  { opacity: 0.72; transform: scale(1.07); }
    100% { opacity: 1;    transform: scale(1); }
}

/* the two blue lights wander on different, slow orbits */
@keyframes vc-login-wander-a {
    from { transform: translate3d(-20%, -27%, 0); }
    to   { transform: translate3d(14%, -8%, 0); }
}

@keyframes vc-login-wander-b {
    from { transform: translate3d(19%, 29%, 0); }
    to   { transform: translate3d(-12%, 10%, 0); }
}

/* a shaft of light sweeps a few degrees about its source and brightens */
@keyframes vc-login-beam {
    from { transform: rotate(calc(var(--r) - 3deg)); opacity: 0.55; }
    to   { transform: rotate(calc(var(--r) + 3deg)); opacity: 1; }
}

/* the badge settles in with a small rise as it fades in (the fade itself is
   on its layer) */
@keyframes vc-login-emblem-in {
    from { transform: translateY(12px) scale(0.97); }
    to   { transform: none; }
}

/* full strength while it is the star of the scene (sharp copy fades out),
   a touch quieter once the login card arrives in front of it (soft copy
   fades in) */
@keyframes vc-login-logo-sharp {
    from { opacity: 0.96; }
    to   { opacity: 0; }
}

@keyframes vc-login-logo-soft {
    from { opacity: 0; }
    to   { opacity: 0.85; }
}

/* dust: ONE smooth path per mote - it rises while swaying side to side
   (1.5 slow S-curves, sampled every 20deg so it reads as a curve, not a
   polyline) and grows a little - plus a fade in / glimmer / fade out over
   the same life. One element, one transform path + one opacity: that is
   the cheapest possible way to move ~16 particles. (Splitting the sway
   onto a second animated layer per mote looked the same but stuttered the
   intro on a CPU slowed 4x.) */
@keyframes vc-login-mote-path {
    0%     { transform: translate3d(0px, 0px, 0) scale(0.70); }
    5.56%  { transform: translate3d(calc(var(--dx, 10px) * 0.500), calc(var(--rise, 80px) * -0.056), 0) scale(0.72); }
    11.11% { transform: translate3d(calc(var(--dx, 10px) * 0.866), calc(var(--rise, 80px) * -0.111), 0) scale(0.75); }
    16.67% { transform: translate3d(calc(var(--dx, 10px) * 1.000), calc(var(--rise, 80px) * -0.167), 0) scale(0.77); }
    22.22% { transform: translate3d(calc(var(--dx, 10px) * 0.866), calc(var(--rise, 80px) * -0.222), 0) scale(0.80); }
    27.78% { transform: translate3d(calc(var(--dx, 10px) * 0.500), calc(var(--rise, 80px) * -0.278), 0) scale(0.82); }
    33.33% { transform: translate3d(0px, calc(var(--rise, 80px) * -0.333), 0) scale(0.85); }
    38.89% { transform: translate3d(calc(var(--dx, 10px) * -0.500), calc(var(--rise, 80px) * -0.389), 0) scale(0.88); }
    44.44% { transform: translate3d(calc(var(--dx, 10px) * -0.866), calc(var(--rise, 80px) * -0.444), 0) scale(0.90); }
    50%    { transform: translate3d(calc(var(--dx, 10px) * -1.000), calc(var(--rise, 80px) * -0.500), 0) scale(0.92); }
    55.56% { transform: translate3d(calc(var(--dx, 10px) * -0.866), calc(var(--rise, 80px) * -0.556), 0) scale(0.95); }
    61.11% { transform: translate3d(calc(var(--dx, 10px) * -0.500), calc(var(--rise, 80px) * -0.611), 0) scale(0.97); }
    66.67% { transform: translate3d(0px, calc(var(--rise, 80px) * -0.667), 0) scale(1.00); }
    72.22% { transform: translate3d(calc(var(--dx, 10px) * 0.500), calc(var(--rise, 80px) * -0.722), 0) scale(1.02); }
    77.78% { transform: translate3d(calc(var(--dx, 10px) * 0.866), calc(var(--rise, 80px) * -0.778), 0) scale(1.05); }
    83.33% { transform: translate3d(calc(var(--dx, 10px) * 1.000), calc(var(--rise, 80px) * -0.833), 0) scale(1.07); }
    88.89% { transform: translate3d(calc(var(--dx, 10px) * 0.866), calc(var(--rise, 80px) * -0.889), 0) scale(1.10); }
    94.44% { transform: translate3d(calc(var(--dx, 10px) * 0.500), calc(var(--rise, 80px) * -0.944), 0) scale(1.13); }
    100%   { transform: translate3d(0px, calc(var(--rise, 80px) * -1.000), 0) scale(1.15); }
}

@keyframes vc-login-mote-fade {
    0%   { opacity: 0; }
    20%  { opacity: var(--a, 0.7); }
    72%  { opacity: calc(var(--a, 0.7) * 0.6); }
    100% { opacity: 0; }
}

/* the Milky Way slides slowly along and across its own axis */
@keyframes vc-login-milky-drift {
    from { transform: translate(-50%, -50%) rotate(-58deg) translate3d(-10%, -4.5%, 0) scale(1.02); }
    to   { transform: translate(-50%, -50%) rotate(-58deg) translate3d(10%, 4.5%, 0) scale(1.08); }
}

@keyframes vc-login-cirrus-drift {
    from { transform: translate(-50%, -50%) translate3d(26%, -34%, 0) rotate(0deg) scale(1); }
    to   { transform: translate(-50%, -50%) translate3d(-20%, 30%, 0) rotate(12deg) scale(1.1); }
}

/* far stars: a gentle sway; mid stars: a moderate one. Different reach and
   pace = parallax (far = little and slow, mid = more, quicker) */
@keyframes vc-login-star-drift-far {
    from { transform: translate3d(-7px, -4px, 0); }
    to   { transform: translate3d(7px, 4px, 0); }
}

@keyframes vc-login-star-drift {
    from { transform: translate3d(-24px, -15px, 0); }
    to   { transform: translate3d(24px, 15px, 0); }
}

/* a glimmer, not a flash: a cluster dips to 25% at most, eased both ways */
@keyframes vc-login-twinkle {
    from { opacity: 0.25; }
    to   { opacity: 1; }
}


/* generic step: fade + gentle rise */
@keyframes vc-login-rise {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
}

/* the visibility half of every step (run as a 0s step at the step's delay):
   hidden - so it cannot take focus - until the step starts, then visible */
@keyframes vc-login-reveal-vis {
    from { visibility: hidden; }
    to   { visibility: visible; }
}

/* inline phone panel: fade + rise, focusable from the first frame */
@keyframes vc-login-panel-in {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
}

/* step 2: greeting - fade + rise + un-blur, with its golden glow */
@keyframes vc-login-hare-in {
    from {
        opacity: 0;
        transform: translateY(12px) scale(0.94);
        filter: blur(8px) drop-shadow(0 0 0 rgba(214, 178, 110, 0));
    }
    to {
        opacity: 1;
        transform: none;
        filter: blur(0) drop-shadow(0 0 14px rgba(214, 178, 110, 0.45));
    }
}

/* step 4: card - fade + small rise + soft scale (it is centred with the
   grid, not with a transform, so this never moves its final position) */
@keyframes vc-login-card-in {
    from { opacity: 0; transform: translateY(12px) scale(0.975); }
    to   { opacity: 1; transform: none; }
}
