/* Startup intro / load screen — "Morph aperture".
   Pure HTML + CSS (+ an inline SVG filter) so it paints during the WASM / WebView boot
   window, BEFORE Blazor and the Morph engine are alive. splash.js fades + removes it the
   moment the app mounts. Reuses the Morph theme tokens from morph.bundle.css.

   Sequence (see artifacts/splash-storyboard): a tiny speck scales in (centre, high), holds a
   beat, then glides down to centre WHILE scaling up into the board; the A.Box wordmark insets
   in (fades/deepens, like Morph Inset — no slide); a purple Morph-cutout dot opens as the
   punctuation (floor + bevel ring, aperture-opens like Morph Cutout).

   Every timing/size is a CSS variable (the "knobs") so it can be tuned live by
   splash-tuner.html without touching keyframes. The values here are the baked defaults. */

#splash {
    /* ---- knobs ------------------------------------------------------------ */
    --lead-in: 0.25s;          /* empty-screen beat before anything starts (added to every delay) */
    --spawn-y: -22vh;          /* how high above centre the speck appears      */
    --speck: 20px;             /* speck diameter                               */
    --pop: 0.5s;               /* speck scale-PUNCH duration                   */
    --pop-ease: cubic-bezier(0.45, 0.05, 0.35, 1);  /* grows visibly from nothing up to the
                                  overshoot — NOT an ease-out (that front-loads to ~full in a
                                  frame and reads as "spawned flat"); starts slow so the scale-in
                                  is seen, then accelerates into the overshoot */
    --pop-overshoot: 1.6;      /* how far past full size the punch overshoots  */
    --hold: 0.5s;              /* beat it holds at spawn before travelling     */
    --travel: 1.7s;            /* glide-down + scale-up duration               */
    --travel-ease: cubic-bezier(0.4, 0, 0.2, 1);   /* easing of the DOWNWARD GLIDE */
    --grow-ease: cubic-bezier(0.75, 0, 0.95, 0.12); /* easing of the SIZE GROWTH —
                                  ease-in keeps it a small speck most of the way down,
                                  then it balloons into the board near the end */
    --grow-delay: 0.5s;        /* hold as a dot this long INTO the glide before growing —
                                  the size growth is compressed into the remaining travel */
    --word-size: clamp(80px, 18vmin, 120px);
    --word-delay: 2.6s;        /* when the wordmark starts to inset in         */
    --word-dur: 0.7s;          /* how long the inset fade takes                */
    --word-ease: cubic-bezier(0.33, 0, 0.3, 1);
    --dot-delay: 3.3s;         /* when the cutout dot opens                    */
    --dot-dur: 0.95s;          /* spawn + bump + hold + expand (slow enough to read) */
    /* exit choreography (cutout close + text out together → board melt); the melt finishes ≈ 1.2s
       after .splash--exit — splash.js reads that off the board's animationend (MELT_END is its
       fallback), then holds the empty screen for EMPTY_HOLD. */
    --close-dur: 0.55s;        /* exit 1: cutout dot custom close (collapse, hold, shut)  */
    --text-out-delay: 0s;      /* exit 1: wordmark fades + scales out alongside the close */
    --text-out-dur: 0.45s;
    --melt-delay: 0.6s;        /* exit 2: board melts once the dot + text are gone        */
    --melt-dur: 0.6s;          /* engine raise-out, slowed from the 440ms RaisedStyle default so
                                  the flatten reads at this large hero scale (but kept brisk)     */
    --melt-ease: cubic-bezier(0.52, 0, 0.74, 0.25);  /* Morph raised ExitEase            */

    /* the settled board (the speck grows INTO these) */
    --board-w: min(88vw, 760px);
    --board-h: min(84vh, 600px);
    --board-r: clamp(26px, 5vmin, 44px);
    --speck-shadow:
        3px 3px 7px var(--shadow-dark, rgba(166, 143, 108, 0.72)),
        -3px -3px 7px var(--shadow-light, rgba(255, 255, 255, 0.95)),
        inset 1px 1px 1px rgba(255, 255, 255, 0.5),
        inset -1.5px -1.5px 2px rgba(166, 143, 108, 0.25);
    /* --lift-driven, exactly like the engine's .neu-raised (raised.css): every offset/blur is
       scaled by --lift, so the engine's raise-out keyframe (--lift → 0) flattens this board into
       the surface for free. --lift defaults to 1 (the @property in morph.bundle's theme.css); it's
       pinned on .splash__board below. */
    --board-shadow:
        calc(var(--lift) * 18px) calc(var(--lift) * 18px) calc(var(--lift) * 42px) var(--shadow-dark, rgba(166, 143, 108, 0.72)),
        calc(var(--lift) * -16px) calc(var(--lift) * -16px) calc(var(--lift) * 38px) var(--shadow-light, rgba(255, 255, 255, 0.95)),
        inset calc(var(--lift) * 2px) calc(var(--lift) * 2px) calc(var(--lift) * 4px) rgba(255, 255, 255, 0.5),
        inset calc(var(--lift) * -3px) calc(var(--lift) * -3px) calc(var(--lift) * 7px) rgba(166, 143, 108, 0.18);
    /* ----------------------------------------------------------------------- */

    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg, #e7ddcd);
    /* Plain fade-out — the escape-hatch exit (boot error / hard timeout / reduced motion). The
       normal exit is the melt below; this is the "get out of the way fast" path. */
    opacity: 1;
    transition: opacity 520ms ease, visibility 520ms ease;
}

#splash.splash--done {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

/* Normal exit — a STAGED close that follows the Morph exit grammar (mirrors the entry):
     1. the cutout dot runs its custom CLOSE — collapse to a seed, hold, then shut (the mirror of
        its open: see cutout-close-ring in cutout.css) — WHILE the wordmark FADES + SCALES out;
     2. then the board (the background surface) MELTS back to the empty --bg with the engine's
        raise-out keyframe verbatim — its depth FLATTENS into the surface (--lift → 0) while it
        fades, using Morph's raised exit ease/duration. Identical to any .neu-raised surface exit.
   The #splash background stays --bg throughout, so what's left is the empty screen; splash.js then
   removes the node and the app (whose background is the same --bg) shows through seamlessly. */
#splash.splash--exit .splash__dot {
    animation: splash-dot-close var(--close-dur) linear both;
}

#splash.splash--exit .splash__text {
    animation: splash-text-out var(--text-out-dur) cubic-bezier(0.4, 0, 0.7, 0.4) var(--text-out-delay) both;
}

#splash.splash--exit .splash__board {
    animation: raise-out var(--melt-dur) var(--melt-ease) var(--melt-delay) both;
}

/* Cutout close — the mirror of splash-dot-open: collapse from full to the seed, hold, then shut. */
@keyframes splash-dot-close {
    0%   { transform: scale(1);   animation-timing-function: cubic-bezier(0.34, 1.23, 0.4, 1); }
    58%  { transform: scale(0.2); animation-timing-function: linear; }
    76%  { transform: scale(0.2); animation-timing-function: cubic-bezier(0.2, 0.9, 0.25, 1.25); }
    100% { transform: scale(0); }
}

@keyframes splash-text-out {
    0%   { opacity: 1; transform: scale(1); }
    100% { opacity: 0; transform: scale(0.7); }
}

/* Off-DOM host for the engrave <filter>; never painted itself. */
.splash__defs {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

/* The board. BASE (un-animated) state is the final, settled board — also what
   prefers-reduced-motion shows. Two intro animations run back-to-back: a scale-in at spawn,
   then a travel that glides to centre while growing into this base size. */
.splash__board {
    --lift: 1;                 /* engine raised depth (drives --board-shadow); raise-out melts it to 0 */
    width: var(--board-w);
    height: var(--board-h);
    border-radius: var(--board-r);
    background: var(--surface, #ece3d5);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    box-shadow: var(--board-shadow);
    animation:
        splash-pop var(--pop) linear var(--lead-in) both,
        splash-glide var(--travel) var(--travel-ease) calc(var(--lead-in) + var(--pop) + var(--hold)) forwards,
        splash-grow max(0ms, var(--travel) - var(--grow-delay)) var(--grow-ease) calc(var(--lead-in) + var(--pop) + var(--hold) + var(--grow-delay)) forwards;
}

/* Scale PUNCH in at spawn (centre, high): grow from nothing, overshoot a bit past full
   (--pop-overshoot), then settle back to 1. Stays a tiny speck; the gap before travel starts
   is the --hold beat. --pop-ease shapes the punch-in; the settle-back is a fixed soft curve. */
@keyframes splash-pop {
    0% {
        width: var(--speck); height: var(--speck); border-radius: 50%;
        transform: translate(0, var(--spawn-y)) scale(0);
        opacity: 0;
        box-shadow: var(--speck-shadow);
        animation-timing-function: var(--pop-ease);
    }
    60% {
        width: var(--speck); height: var(--speck); border-radius: 50%;
        transform: translate(0, var(--spawn-y)) scale(var(--pop-overshoot));
        opacity: 1;
        box-shadow: var(--speck-shadow);
        animation-timing-function: cubic-bezier(0.34, 0, 0.4, 1);
    }
    100% {
        width: var(--speck); height: var(--speck); border-radius: 50%;
        transform: translate(0, var(--spawn-y)) scale(1);
        opacity: 1;
        box-shadow: var(--speck-shadow);
    }
}

/* Position glide and size growth are SEPARATE animations so each carries its own easing: the
   glide (--travel-ease) shapes the descent, the growth (--grow-ease) shapes the scaling. A
   back-loaded --grow-ease keeps it a small speck most of the way down, then balloons it into
   the board right at the end. splash-grow pins the board size/shadow EXPLICITLY at 100% so it
   doesn't inherit the speck size held by splash-pop's forwards-fill. */
@keyframes splash-glide {
    0%   { transform: translate(0, var(--spawn-y)); }
    100% { transform: translate(0, 0); }
}

@keyframes splash-grow {
    0% {
        width: var(--speck); height: var(--speck); border-radius: 50%;
        box-shadow: var(--speck-shadow);
    }
    100% {
        width: var(--board-w); height: var(--board-h); border-radius: var(--board-r);
        box-shadow: var(--board-shadow);
    }
}


/* Wordmark — "A" + cutout dot + "Box", baseline-aligned, scales with font-size. */
.splash__word {
    display: inline-flex;
    align-items: baseline;
    gap: 0.06em;
    font: 800 var(--word-size)/1 'Segoe UI', system-ui, sans-serif;
    letter-spacing: 0.01em;
}

/* The carved letters — a real inset (dark top rim, light bottom rim, recessed floor) via the
   inline SVG <filter>. Like Morph Inset, they INSET in: a plain opacity fade with no slide,
   scale, or blur (the engrave is static, so the filter is computed once — no per-frame jank).
   Against the flat board, fading the carve in reads as the recess deepening into place. */
.splash__text {
    color: var(--surface, #ece3d5);
    filter: url(#splash-engrave);
    animation: splash-word var(--word-dur) var(--word-ease) calc(var(--lead-in) + var(--word-delay)) both;
}

@keyframes splash-word {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* The dot: Morph's purple cutout, as a circle. Two layers, ported from
   src/ABox.Morph/Styles/Cutout/cutout.css — a purple gradient FLOOR and a beveled RING —
   sized in em so they track the wordmark, on the baseline so the dot reads as a period. */
.splash__dot {
    /* 0.75em shrinks the whole dot — and its em-based bevel/lip — by 25% in one move, keeping
       every proportion (the bevel thickness tracks this font-size, not the wordmark's). */
    font-size: 0.75em;
    width: 0.5em;
    height: 0.5em;
    position: relative;
    border-radius: 50%;
    margin-bottom: 0.02em;
    /* Cutout "aperture opens": the ring pops as a seed point, holds, then scales open. */
    animation: splash-dot-open var(--dot-dur) linear calc(var(--lead-in) + var(--dot-delay)) both;
}

.splash__dot-floor,
.splash__dot-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
}

/* The recessed brand surface. Purple from the very first frame of the seed — it scales up with
   the dot (splash-dot-open), so the seed already reads as a tiny purple cutout that grows, rather
   than a grey bevel that fills in. (No clip-path reveal: the parent's scale(0) gates it until the
   dot's turn, then it spawns/bumps/holds/expands as one purple disc.) */
.splash__dot-floor {
    background:
        radial-gradient(120% 120% at 18% 12%, rgba(20, 10, 45, 0.32) 0%, rgba(20, 10, 45, 0) 45%),
        linear-gradient(150deg, rgb(102, 102, 225) 0%, rgb(166, 121, 251) 100%);
}

/* The bevel — deep dark inner shadow top-left, faint light bottom-right (a real cut edge). */
.splash__dot-ring {
    box-shadow:
        inset 0.11em 0.15em 0.20em rgba(18, 8, 38, 0.9),
        inset 0.05em 0.07em 0.09em rgba(18, 8, 38, 0.7),
        inset -0.11em -0.11em 0.18em rgba(18, 8, 38, 0.06),
        inset -0.03em -0.03em 0.03em rgba(255, 255, 255, 0.4);
}

/* The raised outer lip around the aperture (cutout-ring::before). */
.splash__dot-ring::before {
    content: "";
    position: absolute;
    inset: -0.04em;
    border-radius: 50%;
    pointer-events: none;
    box-shadow:
        inset 0.05em 0.05em 0 0 rgba(255, 255, 255, 0.5),
        inset -0.05em -0.05em 0 0 rgba(70, 60, 110, 0.3),
        0 0.04em 0.03em rgba(255, 255, 255, 0.4);
}

/* Same shape as the engine's cutout open (cutout.css) — a seed point appears, holds, then opens —
   but as a solid purple disc that scales, so the purple reads from the seed: the dot SPAWNS,
   BUMPS past its resting size and settles back, HOLDS a beat, then EXPANDS open past full
   (OVERSHOOT) and settles. Seed rests at 0.2 — the cutout's 8% would vanish on a ~0.5em dot. */
@keyframes splash-dot-open {
    0%   { transform: scale(0);    animation-timing-function: cubic-bezier(0.2, 0.85, 0.3, 1); }   /* spawn → bump */
    17%  { transform: scale(0.32); animation-timing-function: cubic-bezier(0.45, 0, 0.5, 1); }      /* bump peak → settle */
    32%  { transform: scale(0.2);  animation-timing-function: linear; }                             /* settled seed */
    52%  { transform: scale(0.2);  animation-timing-function: cubic-bezier(0.32, 0.7, 0.4, 1); }    /* hold, then expand */
    84%  { transform: scale(1.12); animation-timing-function: cubic-bezier(0.3, 0, 0.45, 1); }      /* overshoot past full */
    100% { transform: scale(1); }                                                                  /* settle back */
}

/* Accessibility: honour the same no-motion contract the Morph engine does — skip the
   intro entirely and show the settled board (its base state) which fades out on handoff. */
@media (prefers-reduced-motion: reduce) {
    .splash__board,
    .splash__text,
    .splash__dot,
    #splash.splash--exit .splash__dot,
    #splash.splash--exit .splash__text,
    #splash.splash--exit .splash__board {
        animation: none;
    }
}

/* Dark mode. The board's bevels follow the tokens (--shadow-dark/light, --bg, --surface) for
   free, but the wordmark's SVG engrave bakes light-surface flood colors, so a carve would read
   as floating tan letters on the dark board. Drop the filter and render the wordmark as plain
   light text (--text) — the inset opacity-fade still plays; we just trade the carve for legibility
   on dark. (The pre-paint theme script sets data-theme before this paints, so there's no flash.) */
:root[data-theme="dark"] .splash__text {
    filter: none;
    color: var(--text);
}
