/* ---------------------------------------------------------------------------
   profile-fx.css — the optional "page fx" layer on bio pages.

   Five independent, per-name opt-ins (all premium, all stored on the bio's
   jsonb config):
     1. tap-to-enter gate  (#fx-gate)       — blurred door you tap to open
     2. cursor trail       (body.fx-trail-*) — sparkle/bubble pointer trail
     3. custom cursor      (--fx-cursor)     — your own pointer sprite
     4. badge tint         (--fx-badge-tint) — recolour the badge icons
     5. custom badge       (--fx-badge-icon) — swap in your own badge art
   Plus the site-wide "want your own?" CTA pill (body has .fx-cta).

   Everything here degrades cleanly: no JS and the gate never renders, the
   trail/tint do nothing on their own, and prefers-reduced-motion stills all
   motion. Tokens read the theme's --p-* palette so fx colour-match the skin.
   --------------------------------------------------------------------------- */

/* ---------- 1. tap-to-enter gate ---------- */

/* The page underneath is dimmed + blurred; the gate is a full-bleed veil with
   the "tap anywhere" affordance. Dismissed by ui-4.js (profile-fx wiring). */
.fx-gate {
    position: fixed;
    inset: 0;
    z-index: 2147482000;
    display: grid;
    place-items: center;
    background: rgba(4, 2, 2, .55);
    backdrop-filter: blur(26px) saturate(1.2);
    -webkit-backdrop-filter: blur(26px) saturate(1.2);
    cursor: pointer;
    animation: fx-gate-in .5s ease both;
}

@keyframes fx-gate-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.fx-gate-ring {
    position: absolute;
    width: min(46vmin, 340px);
    height: min(46vmin, 340px);
    border-radius: 50%;
    border: 1px solid var(--p-line-accent, rgba(255, 255, 255, .2));
    animation: fx-gate-pulse 2.6s ease-in-out infinite;
}

@keyframes fx-gate-pulse {
    0%, 100% { transform: scale(.92); opacity: .5; }
    50%      { transform: scale(1.06); opacity: 1; }
}

.fx-gate-mark {
    display: grid;
    place-items: center;
    gap: 1.1rem;
    text-align: center;
}

.fx-gate-logo {
    width: clamp(74px, 16vmin, 116px);
    height: clamp(74px, 16vmin, 116px);
    object-fit: contain;
    filter: drop-shadow(0 0 26px var(--p-accent-glow, rgba(196, 30, 30, .5)));
    animation: fx-gate-breathe 1.9s ease-in-out infinite;
}

@keyframes fx-gate-breathe {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.07); }
}

.fx-gate-hint {
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .34em;
    text-transform: uppercase;
    color: var(--p-ink);
    padding-left: .34em;
    opacity: .8;
    animation: fx-gate-blink 1.9s ease-in-out infinite;
}

@keyframes fx-gate-blink {
    0%, 100% { opacity: .35; }
    50%      { opacity: .95; }
}

.fx-gate-owner {
    font-size: .7rem;
    color: var(--p-muted);
    letter-spacing: .04em;
}

/* Dismissal: JS adds .is-opening, then removes the node. The veil fades out
   while the page beneath un-blurs, so the "door opens" read. */
.fx-gate.is-opening {
    animation: fx-gate-out .55s cubic-bezier(.2, .7, .2, 1) both;
    pointer-events: none;
}

@keyframes fx-gate-out {
    from { opacity: 1; backdrop-filter: blur(26px) saturate(1.2); }
    to   { opacity: 0; backdrop-filter: blur(0) saturate(1); }
}

/* While the gate is up, the real page sits slightly recessed. */
/* The page sits slightly recessed while the veil is up. Scoped with :has() on
   the veil itself rather than a body class, because the class outlives the
   dismissal and a permanently transformed .bb-main breaks the editor's
   100dvh sizing. Never target .profile-page: a transform there becomes the
   containing block for the owner's fixed Edit pill (same trap as the ui-4
   page animation). */
body:has(> #fx-gate) .bb-main {
    transform: scale(.985);
    transition: transform .55s cubic-bezier(.2, .7, .2, 1);
}

/* The editor outranks the entrance veil: it sits above it and owns the
   viewport while open, so the veil must not paint over (or eat clicks on)
   the owner's controls. Owners still see it in view mode. */
body.dash-on .fx-gate {
    display: none;
}

/* ---------- 2. cursor trail ---------- */

/* A fixed canvas sits above the page (below the loader) and paints the trail.
   Only exists when a trail style is on, so no idle cost. */
.fx-trail {
    position: fixed;
    inset: 0;
    z-index: 2147481000;
    pointer-events: none;
}

/* A trail sits *beside* the pointer; the native cursor stays visible. Only a
   custom sprite replaces it, because then the sprite *is* the pointer. */
body.fx-cursor-icon,
body.fx-cursor-icon * {
    cursor: var(--fx-cursor) var(--fx-cursor-x, 4) var(--fx-cursor-y, 4), auto;
}

/* ---------- 3. per-badge colour + custom art ---------- */

/* Recolouring is per badge, applied inline on that one <img> (app.py derives
   the hue/sat from the chosen hex), so the Premium badge can go gold while
   Verified stays default. Custom art replaces the image, so it isn't tinted. */
.badge-icon[data-fx-colour] {
    filter: var(--fx-badge-filter, none);
    transition: filter .18s ease;
}

/* Badge hover lift, so a recoloured badge still reads as interactive. */
.profile-badges .badge-icon:hover {
    filter: var(--fx-badge-filter, none) brightness(1.15) drop-shadow(0 3px 12px var(--p-accent-glow, rgba(196, 30, 30, .5)));
    transform: translateY(-1px);
}

.profile-badges .badge-icon {
    transition: filter .18s ease, transform .18s ease;
}

/* ---------- 5. the "want your own?" CTA ---------- */

/* Bottom-centre floating pill on every bio page. Mirrors the owner edit pill
   (bottom-right) so the two never collide. */
.fx-cta {
    position: fixed;
    left: 50%;
    bottom: calc(18px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%);
    z-index: 960;
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .95rem;
    border-radius: 999px;
    border: 1px solid var(--p-line-accent, rgba(255, 255, 255, .18));
    background: var(--p-btn-bg, rgba(255, 255, 255, .06));
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 12px 30px -14px rgba(0, 0, 0, .85);
    color: var(--p-ink);
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .01em;
    text-decoration: none;
    white-space: nowrap;
    transition: transform .18s cubic-bezier(.2, .7, .2, 1), border-color .18s ease;
}

.fx-cta:hover {
    transform: translateX(-50%) translateY(-2px);
    border-color: var(--p-accent, var(--blood-bright));
}

.fx-cta-slash {
    color: var(--p-muted);
    font-weight: 500;
}

.fx-cta-name {
    font-weight: 800;
    letter-spacing: -.01em;
}

.fx-cta-cta {
    color: var(--p-accent, var(--blood-bright));
    font-weight: 700;
}

.fx-cta-logo {
    width: 15px;
    height: 15px;
    object-fit: contain;
}

/* Owners already have the editor — no upsell pill for them, and none while
   the dashboard is open. */
body.owner-view .fx-cta,
body.dash-on .fx-cta {
    display: none;
}

/* ---------- accessibility ---------- */

@media (prefers-reduced-motion: reduce) {
    .fx-gate-ring,
    .fx-gate-logo,
    .fx-gate-hint {
        animation: none;
    }
    .fx-gate,
    .fx-gate.is-opening {
        animation: none;
    }
    body:has(> #fx-gate) .bb-main {
        transform: none;
        transition: none;
    }
    .fx-cta {
        transition: none;
    }
}

/* Touch devices have no hover cursor — the CTA pill would just sit over the
   owner's edit pill on small screens, so tuck it above the safe area only
   when there is room and drop the hover-lift dependency. */
@media (max-width: 560px) {
    .fx-cta {
        font-size: .7rem;
        padding: .42rem .8rem;
    }
}
