/**
 * CalSchedule landing-page scenes.
 *
 * Motion for the nine illustrations in public/views/partials-scenes.php. Nine
 * of these share one page, so every loop here is long (4-11s), small in
 * amplitude and low in contrast. The page should feel quietly alive, not
 * animated: no single scene may pull the eye away from the copy beside it.
 *
 * Every declared value is the FINISHED state of its animation - opacity 1, no
 * transform, stroke-dashoffset 0 - so switching the animation off (reduced
 * motion, or an old browser) leaves a complete, correct picture. Entrances
 * that carry a delay use animation-fill-mode: backwards so they do not flash
 * their end state before starting.
 *
 * Keyframe names are all prefixed bfz-sc- so they cannot collide with
 * bfz-graphics.css, which loads alongside this file.
 */

/* ------------------------------- Canvas ------------------------------- */

.bfz-app .bfz-sc {
	display: block;
	width: 100%;
	height: auto;
	max-width: 460px;
	overflow: visible;
}

/* ---------------------------- Delay ladder ---------------------------- */

/*
 * One shared stagger, used by whatever animation an element carries. Kept
 * under a second so a staggered group still reads as a single gesture.
 */
.bfz-app .bfz-sc--d1 { animation-delay: .12s; }
.bfz-app .bfz-sc--d2 { animation-delay: .24s; }
.bfz-app .bfz-sc--d3 { animation-delay: .36s; }
.bfz-app .bfz-sc--d4 { animation-delay: .48s; }
.bfz-app .bfz-sc--d5 { animation-delay: .62s; }
.bfz-app .bfz-sc--d6 { animation-delay: .76s; }
.bfz-app .bfz-sc--d7 { animation-delay: .92s; }
.bfz-app .bfz-sc--d8 { animation-delay: 1.08s; }

/* ------------------------------ Drifting ------------------------------ */

/* Backdrop blobs and the small cards that float beside the main object. */
.bfz-app .bfz-sc__float {
	animation: bfz-sc-float 11s ease-in-out infinite;
}

@keyframes bfz-sc-float {
	0%, 100% { transform: translate(0, 0); }
	50%      { transform: translate(3px, -6px); }
}

/* Loose motes in the background. */
.bfz-app .bfz-sc__drift {
	animation: bfz-sc-drift 13s ease-in-out infinite;
}

@keyframes bfz-sc-drift {
	0%, 100% { transform: translate(0, 0); opacity: .35; }
	50%      { transform: translate(-5px, -9px); opacity: .6; }
}

/* A card breathing on the spot. */
.bfz-app .bfz-sc__lift {
	animation: bfz-sc-lift 9s ease-in-out infinite;
}

@keyframes bfz-sc-lift {
	0%, 100% { transform: translateY(0); }
	50%      { transform: translateY(-4px); }
}

/* ----------------------------- Entrances ------------------------------ */

/* Fades up from just below, rests for most of the loop, then resets. */
.bfz-app .bfz-sc__rise {
	opacity: 1;
	transform: none;
	animation: bfz-sc-rise 8s ease-in-out infinite backwards;
}

@keyframes bfz-sc-rise {
	0%, 6%   { opacity: 0; transform: translateY(7px); }
	18%, 90% { opacity: 1; transform: translateY(0); }
	100%     { opacity: 0; transform: translateY(7px); }
}

/* Scales in with the smallest of overshoots. */
.bfz-app .bfz-sc__pop {
	opacity: 1;
	transform: none;
	transform-box: fill-box;
	transform-origin: center;
	animation: bfz-sc-pop 8s ease-in-out infinite backwards;
}

@keyframes bfz-sc-pop {
	0%, 6%   { opacity: 0; transform: scale(.72); }
	16%      { opacity: 1; transform: scale(1.06); }
	22%, 90% { opacity: 1; transform: scale(1); }
	100%     { opacity: 0; transform: scale(.72); }
}

/* Slides up out of an envelope and settles. */
.bfz-app .bfz-sc__slide-up {
	opacity: 1;
	transform: none;
	animation: bfz-sc-slide-up 10s ease-in-out infinite backwards;
}

@keyframes bfz-sc-slide-up {
	0%, 8%   { opacity: .25; transform: translateY(20px); }
	26%, 90% { opacity: 1;   transform: translateY(0); }
	100%     { opacity: .25; transform: translateY(20px); }
}

/* Crosses the gap between the two calendars. */
.bfz-app .bfz-sc__travel {
	opacity: 1;
	transform: none;
	animation: bfz-sc-travel 9s ease-in-out infinite backwards;
}

@keyframes bfz-sc-travel {
	0%, 10%  { opacity: 0; transform: translateX(-4px); }
	24%      { opacity: 1; transform: translateX(6px); }
	64%      { opacity: 1; transform: translateX(50px); }
	80%, 100% { opacity: 0; transform: translateX(58px); }
}

/* ------------------------------ Breathing ----------------------------- */

/* Soft shapes behind a surface. */
.bfz-app .bfz-sc__fade {
	animation: bfz-sc-fade 9s ease-in-out infinite;
}

@keyframes bfz-sc-fade {
	0%, 100% { opacity: .55; }
	50%      { opacity: 1; }
}

/* Outlines and accents: a narrower swing than __fade. */
.bfz-app .bfz-sc__glow {
	animation: bfz-sc-glow 6s ease-in-out infinite;
}

@keyframes bfz-sc-glow {
	0%, 100% { opacity: .62; }
	50%      { opacity: 1; }
}

/* Dots, avatars and markers. */
.bfz-app .bfz-sc__pulse {
	opacity: 1;
	transform-box: fill-box;
	transform-origin: center;
	animation: bfz-sc-pulse 5.5s ease-in-out infinite;
}

@keyframes bfz-sc-pulse {
	0%, 100% { opacity: .6; transform: scale(.84); }
	50%      { opacity: 1;  transform: scale(1); }
}

/* An expanding ring, for a press. */
.bfz-app .bfz-sc__ring {
	opacity: 0;
	transform-box: fill-box;
	transform-origin: center;
	animation: bfz-sc-ring 7s ease-out infinite;
}

@keyframes bfz-sc-ring {
	0%, 40%  { opacity: 0;   transform: scale(.5); }
	52%      { opacity: .75; transform: scale(.8); }
	78%, 100% { opacity: 0;  transform: scale(1.9); }
}

/* A caret in the field being filled in. */
.bfz-app .bfz-sc__blink {
	opacity: 1;
	animation: bfz-sc-blink 2.4s steps(1, end) infinite;
}

@keyframes bfz-sc-blink {
	0%, 55%   { opacity: 1; }
	56%, 100% { opacity: .12; }
}

/* ------------------------------- Strokes ------------------------------ */

/* Drawn in, held, reset. Needs pathLength="1" on the path. */
.bfz-app .bfz-sc__draw {
	stroke-dasharray: 1;
	stroke-dashoffset: 0;
	animation: bfz-sc-draw 8s ease-in-out infinite;
}

@keyframes bfz-sc-draw {
	0%, 10%  { stroke-dashoffset: 1; }
	30%, 90% { stroke-dashoffset: 0; }
	100%     { stroke-dashoffset: 1; }
}

/* The confirmation tick, a beat later than everything else. */
.bfz-app .bfz-sc__tick {
	stroke-dasharray: 1;
	stroke-dashoffset: 0;
	animation: bfz-sc-tick 8s ease-in-out infinite;
}

@keyframes bfz-sc-tick {
	0%, 30%  { stroke-dashoffset: 1; }
	46%, 92% { stroke-dashoffset: 0; }
	100%     { stroke-dashoffset: 1; }
}

/* A highlight running along a link. Needs pathLength="1". */
.bfz-app .bfz-sc__shimmer {
	stroke-dasharray: .3 .7;
	stroke-dashoffset: 0;
	animation: bfz-sc-shimmer 5s linear infinite;
	opacity: .9;
}

@keyframes bfz-sc-shimmer {
	0%   { stroke-dashoffset: 1; }
	100% { stroke-dashoffset: 0; }
}

/* A dotted connector crawling towards its destination. */
.bfz-app .bfz-sc__dots {
	stroke-dashoffset: 0;
	animation: bfz-sc-dots 7s linear infinite;
}

@keyframes bfz-sc-dots {
	0%   { stroke-dashoffset: 0; }
	100% { stroke-dashoffset: -15; }
}

/* ------------------------------ Rotation ------------------------------ */

/* Bars growing off a baseline; the element carries a px transform-origin. */
.bfz-app .bfz-sc__grow {
	transform-box: view-box;
	animation: bfz-sc-grow 7s ease-in-out infinite;
}

@keyframes bfz-sc-grow {
	0%, 100% { transform: scaleY(.76); }
	50%      { transform: scaleY(1); }
}

/* A bell, nudged every few seconds. Carries a px transform-origin. */
.bfz-app .bfz-sc__swing {
	transform-box: view-box;
	animation: bfz-sc-swing 7s ease-in-out infinite;
}

@keyframes bfz-sc-swing {
	0%, 66%, 100% { transform: rotate(0deg); }
	71%           { transform: rotate(7deg); }
	77%           { transform: rotate(-5deg); }
	83%           { transform: rotate(3deg); }
	89%           { transform: rotate(-1.5deg); }
}

/* The globe's meridian, flattening and opening so the sphere reads as turning. */
.bfz-app .bfz-sc__turn {
	transform-box: fill-box;
	transform-origin: center;
	animation: bfz-sc-turn 14s linear infinite;
}

@keyframes bfz-sc-turn {
	0%   { transform: scaleX(1); }
	25%  { transform: scaleX(.1); }
	50%  { transform: scaleX(1); }
	75%  { transform: scaleX(.1); }
	100% { transform: scaleX(1); }
}

/* Clock hands. Each carries its own px transform-origin. */
.bfz-app .bfz-sc__hand {
	transform-box: view-box;
	animation: bfz-sc-hand 24s linear infinite;
}

@keyframes bfz-sc-hand {
	0%   { transform: rotate(0deg); }
	100% { transform: rotate(360deg); }
}

/* A speck drifting on its own slow loop. Several per scene, each offset by a
   bfz-sc--dN delay so they never move as one. */
.bfz-app .bfz-sc__mote {
	transform-box: view-box;
	animation: bfz-sc-mote 11s ease-in-out infinite alternate;
}

@keyframes bfz-sc-mote {
	0%   { transform: translate(0, 0); opacity: .35; }
	50%  { transform: translate(5px, -9px); opacity: .7; }
	100% { transform: translate(-4px, 6px); opacity: .4; }
}

/* A rocket flame: scales from its nozzle rather than its middle, so the
   flame lengthens downward instead of growing in both directions. */
.bfz-app .bfz-sc__flame {
	transform-box: view-box;
	animation: bfz-sc-flame 1.1s ease-in-out infinite alternate;
}

@keyframes bfz-sc-flame {
	0%   { transform: scaleY(.82) scaleX(.9); opacity: .75; }
	100% { transform: scaleY(1.12) scaleX(1); opacity: 1; }
}

/* A bar filling from its left edge. Needs a px transform-origin. */
.bfz-app .bfz-sc__grow-x {
	transform-box: view-box;
	animation: bfz-sc-grow-x 6s ease-in-out infinite;
}

@keyframes bfz-sc-grow-x {
	0%, 100% { transform: scaleX(.25); }
	55%      { transform: scaleX(1); }
}

/* Pair with a rotation class to turn the other way, so meshing cogs mesh. */
.bfz-app .bfz-sc--rev {
	animation-direction: reverse;
}

/* A pointer drifting in and pressing. */
.bfz-app .bfz-sc__nudge {
	transform-box: fill-box;
	transform-origin: center;
	animation: bfz-sc-nudge 7s ease-in-out infinite;
}

@keyframes bfz-sc-nudge {
	0%, 18%   { transform: translate(7px, 9px); }
	40%, 46%  { transform: translate(0, 0); }
	50%       { transform: translate(0, 2px) scale(.94); }
	56%, 74%  { transform: translate(0, 0); }
	100%      { transform: translate(7px, 9px); }
}

/* --------------------------- Reduced motion --------------------------- */

@media (prefers-reduced-motion: reduce) {
	.bfz-app .bfz-sc * {
		animation: none !important;
		transition: none !important;
	}

	/* Everything settles on the frame the loop was heading for. */
	.bfz-app .bfz-sc__float,
	.bfz-app .bfz-sc__drift,
	.bfz-app .bfz-sc__lift,
	.bfz-app .bfz-sc__rise,
	.bfz-app .bfz-sc__pop,
	.bfz-app .bfz-sc__slide-up,
	.bfz-app .bfz-sc__travel,
	.bfz-app .bfz-sc__pulse,
	.bfz-app .bfz-sc__grow,
	.bfz-app .bfz-sc__swing,
	.bfz-app .bfz-sc__turn,
	.bfz-app .bfz-sc__hand,
	.bfz-app .bfz-sc__mote,
	.bfz-app .bfz-sc__flame,
	.bfz-app .bfz-sc__grow-x,
	.bfz-app .bfz-sc__nudge {
		transform: none;
	}

	/*
	 * Only the classes that actually drive the opacity property get reset
	 * here. Shapes hold their own transparency in fill-opacity /
	 * stroke-opacity precisely so this rule cannot flatten them - forcing
	 * opacity:1 on a drifting backdrop blob would turn it into a solid disc.
	 */
	.bfz-app .bfz-sc__rise,
	.bfz-app .bfz-sc__pop,
	.bfz-app .bfz-sc__slide-up,
	.bfz-app .bfz-sc__travel,
	.bfz-app .bfz-sc__fade,
	.bfz-app .bfz-sc__glow,
	.bfz-app .bfz-sc__pulse,
	.bfz-app .bfz-sc__blink,
	.bfz-app .bfz-sc__drift {
		opacity: 1;
	}

	.bfz-app .bfz-sc__draw,
	.bfz-app .bfz-sc__tick,
	.bfz-app .bfz-sc__shimmer,
	.bfz-app .bfz-sc__dots {
		stroke-dasharray: none;
		stroke-dashoffset: 0;
	}

	/* The press ring has no resting state worth showing. */
	.bfz-app .bfz-sc__ring {
		opacity: 0;
	}
}

/* ------------------------------ Dark mode ----------------------------- */

/*
 * Paper goes dark and its hairlines lighten. The scenes mark paper with the
 * literal #FFFFFF and hairlines with #E2E8F0, so attribute selectors can find
 * them without a second copy of every shape. White details drawn on top of a
 * coloured fill use #F8FAFC instead and are deliberately left alone here.
 */
@media (prefers-color-scheme: dark) {
	.bfz-app[data-theme="auto"] .bfz-sc rect[fill="#FFFFFF"],
	.bfz-app[data-theme="auto"] .bfz-sc path[fill="#FFFFFF"],
	.bfz-app[data-theme="auto"] .bfz-sc circle[fill="#FFFFFF"],
	.bfz-app[data-theme="auto"] .bfz-sc ellipse[fill="#FFFFFF"] {
		fill: #161C27;
	}

	.bfz-app[data-theme="auto"] .bfz-sc rect[stroke="#E2E8F0"],
	.bfz-app[data-theme="auto"] .bfz-sc path[stroke="#E2E8F0"],
	.bfz-app[data-theme="auto"] .bfz-sc circle[stroke="#E2E8F0"],
	.bfz-app[data-theme="auto"] .bfz-sc ellipse[stroke="#E2E8F0"] {
		stroke: #2C3443;
	}

	/* Ink bars flip hue but keep their opacity, so the hierarchy survives. */
	.bfz-app[data-theme="auto"] .bfz-sc rect[fill="#0F172A"],
	.bfz-app[data-theme="auto"] .bfz-sc path[fill="#0F172A"],
	.bfz-app[data-theme="auto"] .bfz-sc circle[fill="#0F172A"] {
		fill: #CBD5E1;
	}
}
