/**
 * CalSchedule decorative graphics.
 *
 * Gradient icons, their tinted tiles, and the animated scene on the sign-in
 * screen. Shared by the booking page, the dashboard and the landing page, so
 * it is deliberately small and owns nothing but the graphics.
 *
 * Every animation is slow, looping and low-amplitude: it should read as the
 * page being alive, never as something demanding attention. All of it stops
 * under prefers-reduced-motion, leaving the colour intact.
 */

/* ------------------------------ Icons ------------------------------- */

.bfz-app .bfz-gi {
	display: block;
	flex: 0 0 auto;
	overflow: visible;
}

/* Tinted tile the icon sits in. */
.bfz-app .bfz-gtile {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 40px;
	height: 40px;
	border-radius: 12px;
	background: var(--bfz-gtile-bg, rgba(79, 70, 229, .10));
	box-shadow: inset 0 0 0 1px var(--bfz-gtile-ring, rgba(79, 70, 229, .14));
	transition: transform .25s ease, box-shadow .25s ease;
}

.bfz-app .bfz-gtile--indigo  { --bfz-gtile-bg: rgba(79, 70, 229, .10);  --bfz-gtile-ring: rgba(79, 70, 229, .16); }
.bfz-app .bfz-gtile--violet  { --bfz-gtile-bg: rgba(124, 58, 237, .10); --bfz-gtile-ring: rgba(124, 58, 237, .16); }
.bfz-app .bfz-gtile--sky     { --bfz-gtile-bg: rgba(2, 132, 199, .10);  --bfz-gtile-ring: rgba(2, 132, 199, .16); }
.bfz-app .bfz-gtile--emerald { --bfz-gtile-bg: rgba(5, 150, 105, .10);  --bfz-gtile-ring: rgba(5, 150, 105, .16); }
.bfz-app .bfz-gtile--amber   { --bfz-gtile-bg: rgba(217, 119, 6, .10);  --bfz-gtile-ring: rgba(217, 119, 6, .16); }
.bfz-app .bfz-gtile--rose    { --bfz-gtile-bg: rgba(225, 29, 72, .10);  --bfz-gtile-ring: rgba(225, 29, 72, .16); }

.bfz-app .bfz-gtile--lg {
	width: 48px;
	height: 48px;
	border-radius: 14px;
}

/* Lift the tile when its row or card is hovered. */
.bfz-app li:hover > .bfz-gtile,
.bfz-app a:hover .bfz-gtile,
.bfz-app .bfz-land__feature:hover .bfz-gtile,
.bfz-app .bfz-land__step:hover .bfz-gtile {
	transform: translateY(-2px);
	box-shadow: inset 0 0 0 1px var(--bfz-gtile-ring), 0 6px 14px -8px rgba(15, 23, 42, .4);
}

/* -------------------------- Icon animations -------------------------- */

/* Calendar: dots light up in sequence, like a month filling with bookings. */
.bfz-app .bfz-gi__dot {
	animation: bfz-dot 3.6s ease-in-out infinite;
	opacity: .35;
}
.bfz-app .bfz-gi__dot--1 { animation-delay: 0s; }
.bfz-app .bfz-gi__dot--2 { animation-delay: .18s; }
.bfz-app .bfz-gi__dot--3 { animation-delay: .36s; }
.bfz-app .bfz-gi__dot--4 { animation-delay: .54s; }
.bfz-app .bfz-gi__dot--5 { animation-delay: .72s; }

@keyframes bfz-dot {
	0%, 55%, 100% { opacity: .3; }
	18%, 34%      { opacity: 1; }
}

/* Clock: the hand sweeps once, then rests. */
.bfz-app .bfz-gi__hand {
	animation: bfz-sweep 6s cubic-bezier(.45, 0, .2, 1) infinite;
}

@keyframes bfz-sweep {
	0%, 12%   { transform: rotate(0deg); }
	46%, 100% { transform: rotate(360deg); }
}

/* Lock: the shackle lifts a hair and settles, so the icon reads as "this
   opens" rather than "this is sealed". */
.bfz-app .bfz-gi__shackle {
	transform-box: view-box;
	animation: bfz-shackle 5s ease-in-out infinite;
}

@keyframes bfz-shackle {
	0%, 62%, 100% { transform: translateY(0); }
	74%, 86%      { transform: translateY(-1.6px); }
}

/* Rocket: the flame scales from its nozzle, never its middle. */
.bfz-app .bfz-gi__flame {
	transform-box: view-box;
	animation: bfz-gi-flame 1s ease-in-out infinite alternate;
}

@keyframes bfz-gi-flame {
	0%   { transform: scaleY(.76); opacity: .7; }
	100% { transform: scaleY(1.1); opacity: 1; }
}

/* Shield and check: the tick draws itself in. */
.bfz-app .bfz-gi__draw {
	stroke-dasharray: 1;
	stroke-dashoffset: 1;
	animation: bfz-draw 4.5s ease-in-out infinite;
}

/*
 * Rest in the completed state for most of the loop. An icon caught mid-draw
 * reads as broken rather than animated - an envelope loses its flap, a tick
 * disappears - so the incomplete window is kept short and deliberate.
 */
@keyframes bfz-draw {
	0%, 3%    { stroke-dashoffset: 1; }
	26%, 93%  { stroke-dashoffset: 0; }
	100%      { stroke-dashoffset: 1; }
}

/* Camera lens and map pin: a soft breathing pulse. */
.bfz-app .bfz-gi__pulse {
	animation: bfz-breathe 3.2s ease-in-out infinite;
	transform-box: fill-box;
	transform-origin: center;
}

@keyframes bfz-breathe {
	0%, 100% { opacity: .55; transform: scale(.82); }
	50%      { opacity: 1;   transform: scale(1); }
}

.bfz-app .bfz-gi__lens {
	animation: bfz-nudge 3.2s ease-in-out infinite;
	transform-box: fill-box;
	transform-origin: left center;
}

@keyframes bfz-nudge {
	0%, 100% { transform: translateX(0); }
	50%      { transform: translateX(1px); }
}

/* Link: a highlight travels along the chain. */
.bfz-app .bfz-gi__shimmer {
	stroke-dasharray: .35 .65;
	animation: bfz-travel 3s linear infinite;
	opacity: .9;
}

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

/* Bell: a small swing every few seconds. */
.bfz-app .bfz-gi__swing {
	animation: bfz-swing 4.2s ease-in-out infinite;
}

@keyframes bfz-swing {
	0%, 62%, 100%   { transform: rotate(0deg); }
	68%             { transform: rotate(9deg); }
	74%             { transform: rotate(-7deg); }
	80%             { transform: rotate(4deg); }
	86%             { transform: rotate(-2deg); }
}

/* Sparkles: staggered twinkle. */
.bfz-app .bfz-gi__twinkle {
	transform-box: fill-box;
	transform-origin: center;
	animation: bfz-twinkle 3.4s ease-in-out infinite;
}
.bfz-app .bfz-gi__twinkle--1 { animation-delay: 0s; }
.bfz-app .bfz-gi__twinkle--2 { animation-delay: .5s; }
.bfz-app .bfz-gi__twinkle--3 { animation-delay: 1s; }

@keyframes bfz-twinkle {
	0%, 100% { transform: scale(.88); opacity: .6; }
	50%      { transform: scale(1.06); opacity: 1; }
}

/* Bolt: a glow that runs round the outline. */
.bfz-app .bfz-gi__glow {
	animation: bfz-glow 2.8s ease-in-out infinite;
}

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

/* Globe: the meridian rotates, so the sphere reads as turning. */
.bfz-app .bfz-gi__meridian {
	animation: bfz-turn 7s linear infinite;
}

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

/* Bars: grow from the baseline, staggered. */
.bfz-app .bfz-gi__bar {
	animation: bfz-grow 3.4s ease-in-out infinite;
}
.bfz-app .bfz-gi__bar--1 { animation-delay: 0s; }
.bfz-app .bfz-gi__bar--2 { animation-delay: .16s; }
.bfz-app .bfz-gi__bar--3 { animation-delay: .32s; }

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

/*
 * Envelope flap. Drawn with a dash that never fully retracts: without the
 * flap the icon is just a rounded rectangle, so the stroke stays present and
 * only its weight breathes.
 */
.bfz-app .bfz-gi__flap {
	stroke-dasharray: 1;
	stroke-dashoffset: 0;
	animation: bfz-flap 5s ease-in-out infinite;
}

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

/* Person: the shoulders rise into place. */
.bfz-app .bfz-gi__rise {
	stroke-dasharray: 1;
	stroke-dashoffset: 0;
	animation: bfz-breathe-soft 3.6s ease-in-out infinite;
}

@keyframes bfz-breathe-soft {
	0%, 100% { opacity: .8; }
	50%      { opacity: 1; }
}

/* ------------------------------ Scene -------------------------------- */

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

.bfz-app .bfz-scene__blob {
	animation: bfz-float 9s ease-in-out infinite;
	transform-box: fill-box;
	transform-origin: center;
}
.bfz-app .bfz-scene__blob--2 { animation-delay: -4s; animation-duration: 11s; }

@keyframes bfz-float {
	0%, 100% { transform: translate(0, 0) scale(1); }
	50%      { transform: translate(4px, -6px) scale(1.04); }
}

.bfz-app .bfz-scene__card {
	animation: bfz-hover-card 8s ease-in-out infinite;
	transform-box: fill-box;
	transform-origin: center;
}

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

/* Days fill in one after another, then the whole month resets. */
.bfz-app .bfz-scene__day {
	animation: bfz-fill 7s ease-in-out infinite;
}
.bfz-app .bfz-scene__day--1  { animation-delay: .00s; }
.bfz-app .bfz-scene__day--2  { animation-delay: .08s; }
.bfz-app .bfz-scene__day--3  { animation-delay: .16s; }
.bfz-app .bfz-scene__day--4  { animation-delay: .24s; }
.bfz-app .bfz-scene__day--5  { animation-delay: .32s; }
.bfz-app .bfz-scene__day--6  { animation-delay: .40s; }
.bfz-app .bfz-scene__day--7  { animation-delay: .48s; }
.bfz-app .bfz-scene__day--9  { animation-delay: .64s; }
.bfz-app .bfz-scene__day--10 { animation-delay: .72s; }
.bfz-app .bfz-scene__day--11 { animation-delay: .80s; }
.bfz-app .bfz-scene__day--12 { animation-delay: .88s; }
.bfz-app .bfz-scene__day--13 { animation-delay: .96s; }
.bfz-app .bfz-scene__day--14 { animation-delay: 1.04s; }
.bfz-app .bfz-scene__day--15 { animation-delay: 1.12s; }

@keyframes bfz-fill {
	0%, 4%    { opacity: .12; }
	16%, 92%  { opacity: .30; }
	100%      { opacity: .12; }
}

/* The chosen day settles in with a small pop. */
.bfz-app .bfz-scene__pick {
	animation: bfz-pick 7s ease-in-out infinite;
	transform-box: fill-box;
	transform-origin: center;
}

@keyframes bfz-pick {
	0%, 12%   { transform: scale(.72); opacity: .4; }
	20%       { transform: scale(1.12); opacity: 1; }
	26%, 94%  { transform: scale(1); opacity: 1; }
	100%      { transform: scale(.72); opacity: .4; }
}

/* Time slots slide in from the right, one per beat. */
.bfz-app .bfz-scene__slot {
	animation: bfz-slide-in 7s ease-in-out infinite;
	transform-box: fill-box;
	transform-origin: center;
}
.bfz-app .bfz-scene__slot--1 { animation-delay: .1s; }
.bfz-app .bfz-scene__slot--2 { animation-delay: .25s; }
.bfz-app .bfz-scene__slot--3 { animation-delay: .4s; }

@keyframes bfz-slide-in {
	0%, 8%    { transform: translateX(12px); opacity: 0; }
	20%, 92%  { transform: translateX(0); opacity: 1; }
	100%      { transform: translateX(12px); opacity: 0; }
}

/* The confirmation card rises at the end of the loop. */
.bfz-app .bfz-scene__confirm {
	animation: bfz-confirm 7s ease-in-out infinite;
	transform-box: fill-box;
	transform-origin: center;
}

@keyframes bfz-confirm {
	0%, 28%   { transform: translateY(12px); opacity: 0; }
	38%, 94%  { transform: translateY(0); opacity: 1; }
	100%      { transform: translateY(12px); opacity: 0; }
}

.bfz-app .bfz-scene__tick {
	stroke-dasharray: 1;
	stroke-dashoffset: 1;
	animation: bfz-tick 7s ease-in-out infinite;
}

@keyframes bfz-tick {
	0%, 36%   { stroke-dashoffset: 1; }
	48%, 94%  { stroke-dashoffset: 0; }
	100%      { stroke-dashoffset: 1; }
}

.bfz-app .bfz-scene__mote {
	animation: bfz-drift 10s ease-in-out infinite;
	transform-box: fill-box;
	transform-origin: center;
}
.bfz-app .bfz-scene__mote--2 { animation-delay: -3s; animation-duration: 12s; }
.bfz-app .bfz-scene__mote--3 { animation-delay: -6s; animation-duration: 9s; }

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

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

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

	/* Leave everything in its finished state rather than mid-animation. */
	.bfz-app .bfz-gi__dot,
	.bfz-app .bfz-gi__pulse,
	.bfz-app .bfz-gi__glow,
	.bfz-app .bfz-gi__twinkle,
	.bfz-app .bfz-gi__flame,
	.bfz-app .bfz-gi__rise {
		opacity: 1;
	}

	/* The two new transform-driven hooks settle at rest, not mid-move. */
	.bfz-app .bfz-gi__shackle,
	.bfz-app .bfz-gi__flame {
		transform: none;
	}

	.bfz-app .bfz-gi__draw,
	.bfz-app .bfz-gi__flap,
	.bfz-app .bfz-gi__shimmer,
	.bfz-app .bfz-scene__tick {
		stroke-dasharray: none;
		stroke-dashoffset: 0;
	}

	.bfz-app .bfz-scene__slot,
	.bfz-app .bfz-scene__confirm,
	.bfz-app .bfz-scene__pick {
		opacity: 1;
		transform: none;
	}

	.bfz-app .bfz-scene__day {
		opacity: .3;
	}
}

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

@media (prefers-color-scheme: dark) {
	.bfz-app[data-theme="auto"] .bfz-gtile {
		--bfz-gtile-bg: rgba(129, 140, 248, .14);
		--bfz-gtile-ring: rgba(129, 140, 248, .20);
	}

	.bfz-app[data-theme="auto"] .bfz-gtile--emerald { --bfz-gtile-bg: rgba(52, 211, 153, .14); --bfz-gtile-ring: rgba(52, 211, 153, .20); }
	.bfz-app[data-theme="auto"] .bfz-gtile--sky     { --bfz-gtile-bg: rgba(56, 189, 248, .14); --bfz-gtile-ring: rgba(56, 189, 248, .20); }
	.bfz-app[data-theme="auto"] .bfz-gtile--amber   { --bfz-gtile-bg: rgba(251, 191, 36, .14); --bfz-gtile-ring: rgba(251, 191, 36, .20); }
	.bfz-app[data-theme="auto"] .bfz-gtile--rose    { --bfz-gtile-bg: rgba(251, 113, 133, .14); --bfz-gtile-ring: rgba(251, 113, 133, .20); }
	.bfz-app[data-theme="auto"] .bfz-gtile--violet  { --bfz-gtile-bg: rgba(192, 132, 252, .14); --bfz-gtile-ring: rgba(192, 132, 252, .20); }

	/* The scene's paper surfaces need to stop being white in the dark. */
	.bfz-app[data-theme="auto"] .bfz-scene rect[fill="#FFFFFF"] {
		fill: #161C27;
	}

	.bfz-app[data-theme="auto"] .bfz-scene rect[stroke="#E2E8F0"] {
		stroke: #2C3443;
	}
}

/* ---------------------- Dashboard stat tiles ------------------------- */

/*
 * The overview tiles keep their own 30px holder; the tone classes only add
 * colour. These rules carry one extra class so they win over the dashboard
 * stylesheet, which loads after this one.
 */
.bfz-app .bfz-tile__icon.bfz-gtile {
	width: 30px;
	height: 30px;
	border-radius: 9px;
	background: var(--bfz-gtile-bg);
	box-shadow: inset 0 0 0 1px var(--bfz-gtile-ring);
	color: var(--bfz-gtile-ink, var(--bfz-brand));
}

.bfz-app .bfz-tile__icon.bfz-gtile--indigo  { --bfz-gtile-ink: #4F46E5; }
.bfz-app .bfz-tile__icon.bfz-gtile--violet  { --bfz-gtile-ink: #7C3AED; }
.bfz-app .bfz-tile__icon.bfz-gtile--sky     { --bfz-gtile-ink: #0284C7; }
.bfz-app .bfz-tile__icon.bfz-gtile--emerald { --bfz-gtile-ink: #059669; }
.bfz-app .bfz-tile__icon.bfz-gtile--amber   { --bfz-gtile-ink: #B45309; }
.bfz-app .bfz-tile__icon.bfz-gtile--rose    { --bfz-gtile-ink: #E11D48; }

@media (prefers-color-scheme: dark) {
	.bfz-app[data-theme="auto"] .bfz-tile__icon.bfz-gtile--indigo  { --bfz-gtile-ink: #A5B4FC; }
	.bfz-app[data-theme="auto"] .bfz-tile__icon.bfz-gtile--violet  { --bfz-gtile-ink: #C4B5FD; }
	.bfz-app[data-theme="auto"] .bfz-tile__icon.bfz-gtile--sky     { --bfz-gtile-ink: #7DD3FC; }
	.bfz-app[data-theme="auto"] .bfz-tile__icon.bfz-gtile--emerald { --bfz-gtile-ink: #6EE7B7; }
	.bfz-app[data-theme="auto"] .bfz-tile__icon.bfz-gtile--amber   { --bfz-gtile-ink: #FCD34D; }
	.bfz-app[data-theme="auto"] .bfz-tile__icon.bfz-gtile--rose    { --bfz-gtile-ink: #FDA4AF; }
}

/* ------------------- Functional icons stay still ---------------------- */

/*
 * A tick that marks a list item has a job to do. Animating its draw means it
 * is missing for part of every loop, which reads as a rendering fault. Only
 * icons sitting in a decorative tile animate their stroke.
 */
.bfz-app li > .bfz-gi .bfz-gi__draw,
.bfz-app li > .bfz-gi .bfz-gi__flap,
.bfz-app .bfz-land__rowlist .bfz-gi__draw,
.bfz-app .bfz-land__ticks .bfz-gi__draw,
.bfz-app .bfz-land__ctaticks .bfz-gi__draw {
	animation: none;
	stroke-dasharray: none;
	stroke-dashoffset: 0;
}
