/**
 * File: /css/gp-app-splash.css
 *
 * Gymnastics Plus - App Splash Overlay (owner-approved Option B motion)
 * See inc/gp-app-splash.php for the full three-layer defense explanation and
 * docs/plans/2026-07-24-splash-animation-spec.md for the source spec.
 *
 * Colorway (owner decision, 2026-07-24): white background, black wordmark,
 * gold plus is the default in-app colorway. A 'dark' colorway (black-style
 * background, white wordmark, gold plus - the spec's marketing/store-preview
 * variant) is available for review: inc/gp-app-splash.php's gpa_splash_theme()
 * resolves it and stamps [data-splash-theme="dark"] on both the <html> cover
 * (Layer 1, .gp-splash-theme-dark) and the overlay itself (Layer 2). Rules
 * below key off that attribute/class; everything else (keyframes, timings,
 * the white metallic sweep - it reads on gold either way) is unchanged.
 *
 * Tokens consumed: --gp-white, --gp-gray-900, --gp-motion-duration-fast,
 * --gp-motion-ease-out (see assets/css/gp-base.css, loaded site-wide so it is
 * always available here). No raw hex anywhere in this file - colors are
 * Tier-1 primitives with no literal fallback, since a hex fallback would trip
 * the CI "no NEW raw hex in component CSS" guard (this file is not on that
 * guard's exempt list, unlike gp-base.css/gp-core.css themselves).
 */

/* =========================================================================
 * Layer 1 - guaranteed pre-body white cover + pure-CSS auto-die fallback.
 * Armed by the tiny inline script in inc/gp-app-splash.php (wp_head, -95),
 * before any body content can paint. See that file's header comment for why
 * this exists independently of Layer 2 below.
 * ======================================================================= */
html.gp-splash-armed {
	overflow: hidden; /* no scroll under the cover while it plays */
}

html.gp-splash-armed::before {
	content: "";
	position: fixed;
	inset: 0;
	background: var(--gp-white);
	z-index: 2147483647;
	animation: gp-splash-autodie 2.3s 1 forwards;
}

html.gp-splash-armed.gp-splash-theme-dark::before {
	background: var(--gp-gray-900);
}

/* Dark colorway: the fixed ::before cover cannot paint the status-bar /
   safe-area band — iOS fills that from the ROOT element's own background.
   While the dark splash is alive, the root itself goes dark so the top
   inset matches; the class leaves with the same JS/auto-die cleanup, so
   the page returns to its normal background the moment the splash dies. */
html.gp-splash-armed.gp-splash-theme-dark {
	animation: gp-splash-rootdie 2.3s 1 forwards;
}

/* CSS-only death for the root paint: pages without wp_footer (the standalone
   login template) never run the JS cleanup, so the rule must expire on its
   own exactly like the ::before cover does. */
@keyframes gp-splash-rootdie {
	0%, 95% { background: var(--gp-gray-900); }
	100% { background: transparent; }
}

html.gp-splash-armed.gp-splash-reduced::before {
	animation-duration: 1.1s;
}

@keyframes gp-splash-autodie {
	0%, 88%   { opacity: 1; visibility: visible; pointer-events: auto; }
	100%      { opacity: 0; visibility: hidden; pointer-events: none; }
}

/* =========================================================================
 * Layer 2 - the real recomposed logo overlay. Default HIDDEN (display:none)
 * - see inc/gp-app-splash.php for why hidden-by-default is the safer choice
 * when JS might not run. js/gp-app-splash.js adds .is-visible to reveal it,
 * which is what starts every animation below (nothing plays while hidden).
 * ======================================================================= */
.gp-app-splash {
	display: none;
	position: fixed;
	inset: 0;
	z-index: 2147483647;
	background: var(--gp-white);
	align-items: center;
	justify-content: center;
	opacity: 1;
	transition: opacity var(--gp-motion-duration-fast, 200ms) var(--gp-motion-ease-out, cubic-bezier(0.4, 0, 0.2, 1));
}

.gp-app-splash[data-splash-theme="dark"] {
	background: var(--gp-gray-900);
}

.gp-app-splash.is-visible {
	display: flex;
	/* Independent pure-CSS fallback: once visible, this element fades and
	   goes inert on its own fixed timer even if js/gp-app-splash.js throws
	   before it can run its own skip/removal logic. */
	animation: gp-splash-overlay-autodie 2.3s 1 forwards;
}

.gp-app-splash.is-visible.gp-app-splash--reduced {
	animation-duration: 1.1s;
}

@keyframes gp-splash-overlay-autodie {
	0%, 88%   { opacity: 1; pointer-events: auto; }
	100%      { opacity: 0; pointer-events: none; visibility: hidden; }
}

.gp-app-splash--fading {
	opacity: 0 !important;
	pointer-events: none;
}

.gp-app-splash__logo {
	position: relative;
	width: 72vw;
	max-width: 640px;
	aspect-ratio: 4 / 1; /* 400x100 source canvas, keeps the recomposed layers aligned */
}

.gp-app-splash__word,
.gp-app-splash__plus {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
}

.gp-app-splash__sweep {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	background-image: linear-gradient(115deg, transparent 42%, rgba(255, 255, 255, .85) 50%, transparent 58%);
	background-repeat: no-repeat;
	background-size: 260% 100%;
	-webkit-mask-image: var(--gp-splash-plus-mask, none);
	mask-image: var(--gp-splash-plus-mask, none);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-size: 100% 100%;
	mask-size: 100% 100%;
	mix-blend-mode: screen;
	opacity: 0;
	pointer-events: none;
}

/* =========================================================================
 * Motion - exact approved Option B keyframes (spec block reproduced
 * verbatim; class/keyframe names namespaced gp-splash-* here, loop removed
 * for production - each runs "1" iteration only).
 * ======================================================================= */

/* WORDMARK from the front */
.gp-app-splash.is-visible .gp-app-splash__word {
	animation: gp-splash-bw 2s 1 both;
}
@keyframes gp-splash-bw {
	0%   { transform: scale(1.9); opacity: 0; filter: blur(4px); }
	5%   { opacity: .6; }
	22%  { transform: scale(1); opacity: 1; filter: blur(0); } /* 0.45s */
	34%  { transform: scale(1.025); }
	39%  { transform: scale(1); }
	100% { transform: scale(1); opacity: 1; }
}

/* GOLD PLUS from the back */
.gp-app-splash.is-visible .gp-app-splash__plus {
	animation: gp-splash-bp 2s 1 both;
	transform-origin: 93% 50%;
}
@keyframes gp-splash-bp {
	0%, 8% { transform: scale(.3) rotate(-90deg); opacity: 0; filter: blur(4px); }
	13%    { opacity: 1; }
	32%    { transform: scale(1) rotate(0); opacity: 1; filter: blur(0); } /* 0.65s */
	34%    { transform: scale(1.03); }
	39%    { transform: scale(1); }
	100%   { transform: scale(1); opacity: 1; }
}

/* Metallic sweep across the plus only, masked by its own alpha, ~0.75-1.05s of the 2s run */
.gp-app-splash.is-visible .gp-app-splash__sweep {
	animation: gp-splash-sweep 2s 1 both;
}
@keyframes gp-splash-sweep {
	0%, 37%   { background-position: -140% 0; opacity: 0; }
	37.5%     { opacity: .9; } /* 0.75s */
	52.5%     { background-position: 140% 0; } /* 1.05s */
	53%, 100% { opacity: 0; }
}

/* =========================================================================
 * prefers-reduced-motion: static logo, no keyframe motion, shorter hold
 * (~0.8s) then the same fade. Both a class hook (JS-driven, matches the
 * <html> class set by the Layer-1 preboot script) and a bare media query
 * (so a fully JS-less load still respects the OS setting on the 3/4 headers
 * where Layer 2's markup can render without JS at all).
 * ======================================================================= */
.gp-app-splash--reduced .gp-app-splash__word,
.gp-app-splash--reduced .gp-app-splash__plus {
	animation: none;
	transform: none;
	opacity: 1;
	filter: none;
}
.gp-app-splash--reduced .gp-app-splash__sweep {
	animation: none;
	opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
	.gp-app-splash .gp-app-splash__word,
	.gp-app-splash .gp-app-splash__plus {
		animation: none;
		transform: none;
		opacity: 1;
		filter: none;
	}
	.gp-app-splash .gp-app-splash__sweep {
		animation: none;
		opacity: 0;
	}
}
