<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" />
		<meta name="theme-color" content="#0c1620" />
		<meta name="mobile-web-app-capable" content="yes" />
		<meta name="apple-mobile-web-app-capable" content="yes" />
		<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
		<!-- the drake in the tab: the svg is the master, the pngs are rendered
		     from it by scripts/duck-icon.mjs -->
		<link rel="icon" type="image/png" sizes="16x16" href="/duck-16.png" />
		<link rel="icon" type="image/png" sizes="32x32" href="/duck-32.png" />
		<link rel="icon" type="image/svg+xml" href="/duck.svg" />
		<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
		<title>Ententeich</title>
		<!-- the pond's own face, blurred behind the word: the one the card opens
		     on, shot without a duck in it (scripts/loader-shot.mjs) -->
		<link rel="preload" as="image" href="/pond-loader-portrait.jpg" media="(max-aspect-ratio: 1/1)" />
		<link rel="preload" as="image" href="/pond-loader-landscape.jpg" media="(min-aspect-ratio: 1/1)" />
		<style>
			:root {
				color-scheme: dark;
			}
			* {
				margin: 0;
				padding: 0;
				box-sizing: border-box;
			}
			html,
			body {
				height: 100%;
				overflow: hidden;
				background: #0c1620;
				overscroll-behavior: none;
			}
			#app {
				position: fixed;
				inset: 0;
			}
			#app canvas {
				display: block;
				width: 100%;
				height: 100%;
				touch-action: none;
				-webkit-user-select: none;
				user-select: none;
				-webkit-tap-highlight-color: transparent;
			}
			/* the card: the pond it opens on, thrown out of focus behind the word,
			   and gone into the live pond the moment that is ready */
			#loading {
				position: fixed;
				inset: 0;
				display: grid;
				place-items: center;
				overflow: hidden;
				background: #0c1620;
				transition: opacity 0.9s ease;
				z-index: 2;
			}
			#loading.done {
				opacity: 0;
				pointer-events: none;
			}
			#loading.done .loading__line {
				opacity: 0;
				transform: translateY(-5px);
			}
			.loading__photo {
				position: absolute;
				/* over the edges, so the blur's soft border stays off screen */
				inset: -7%;
				background: url('/pond-loader-portrait.jpg') center / 100% 100% no-repeat;
				/* the wash is stretched to the viewport rather than cover-cropped:
				   under this much blur nobody can tell, and it keeps the far shore
				   on the same line of the screen as the live camera's, at any
				   aspect ratio, so the two meet cleanly when the card goes */
				filter: blur(17px) saturate(1.04);
			}
			@media (min-aspect-ratio: 1/1) {
				.loading__photo {
					background-image: url('/pond-loader-landscape.jpg');
				}
			}
			.loading__tint {
				position: absolute;
				inset: 0;
				background:
					radial-gradient(145% 105% at 50% 42%, rgba(8, 20, 30, 0) 28%, rgba(8, 20, 30, 0.4) 100%),
					linear-gradient(180deg, rgba(8, 20, 30, 0.26), rgba(8, 20, 30, 0.08) 38%, rgba(8, 20, 30, 0.3));
			}
			.loading__line {
				position: relative;
				display: flex;
				align-items: baseline;
				gap: 0.46em;
				color: #f4f9fd;
				font: 500 clamp(21px, 5.6vw, 30px) / 1.2 ui-rounded, system-ui, -apple-system, "Segoe UI", sans-serif;
				letter-spacing: 0.13em;
				text-shadow: 0 2px 18px rgba(6, 16, 24, 0.55), 0 0 3px rgba(6, 16, 24, 0.4);
				transition: opacity 0.55s ease, transform 0.9s ease;
			}
			/* "quack ... quack", one piece at a time — the word, then the three
			   dots, then the word again. A piece is fully blended in before the
			   next starts: word 0.38 s, dot 0.2 s, 0.05 s between.
			   0.05-0.43 · 0.48-0.68 · 0.73-0.93 · 0.98-1.18 · 1.23-1.61 */
			.loading__line .word,
			.loading__dots span {
				opacity: 0;
				animation: blend-in 0.38s ease-out forwards;
			}
			.loading__line .word:first-child {
				animation-delay: 0.05s;
			}
			.loading__dots {
				display: inline-flex;
				gap: 0.07em;
			}
			.loading__dots span {
				animation-duration: 0.2s;
			}
			.loading__dots span:nth-child(1) {
				animation-delay: 0.48s;
			}
			.loading__dots span:nth-child(2) {
				animation-delay: 0.73s;
			}
			.loading__dots span:nth-child(3) {
				animation-delay: 0.98s;
			}
			.loading__line .word:last-child {
				animation-delay: 1.23s;
			}
			@keyframes blend-in {
				from {
					opacity: 0;
					filter: blur(6px);
				}
				65% {
					filter: blur(1px);
				}
				to {
					opacity: 1;
					filter: blur(0);
				}
			}
			@media (prefers-reduced-motion: reduce) {
				#loading {
					transition-duration: 0.3s;
				}
				.loading__line .word,
				.loading__dots span {
					animation: none;
					opacity: 1;
				}
			}
			/* the title cards: one line low over the water, hardly a surface at
			   all — the word is the thing, and the pond stays visible through */
			#hints {
				position: fixed;
				left: 0;
				right: 0;
				bottom: calc(18px + env(safe-area-inset-bottom, 0px));
				z-index: 1;
				padding: 0 12px;
				pointer-events: none;
				text-align: center;
			}
			.hint {
				display: inline-block;
				max-width: min(92vw, 30rem);
				margin: 0;
				padding: 0.58rem 0.95rem 0.62rem;
				border: 1px solid rgba(232, 246, 255, 0.16);
				border-radius: 13px;
				background: rgba(8, 18, 26, 0.33);
				-webkit-backdrop-filter: blur(9px) saturate(1.06);
				backdrop-filter: blur(9px) saturate(1.06);
				color: rgba(242, 249, 253, 0.95);
				font: 500 clamp(13px, 3.5vw, 15px) / 1.35 ui-rounded, system-ui, -apple-system, "Segoe UI", sans-serif;
				letter-spacing: 0.022em;
				text-wrap: pretty;
				text-shadow: 0 1px 10px rgba(0, 8, 14, 0.4);
				opacity: 0;
				transform: translateY(7px);
				transition: opacity 0.55s ease, transform 0.55s ease;
			}
			.hint.on {
				opacity: 1;
				transform: translateY(0);
			}
			.hint a {
				color: inherit;
				text-decoration: underline;
				text-decoration-color: rgba(242, 249, 253, 0.42);
				text-decoration-thickness: 1px;
				text-underline-offset: 0.18em;
				pointer-events: auto;
				cursor: pointer;
			}
			.hint a:hover {
				text-decoration-color: currentColor;
			}
			@media (prefers-reduced-motion: reduce) {
				.hint {
					transition-duration: 0.01s;
				}
			}
			.visually-hidden {
				position: absolute;
				width: 1px;
				height: 1px;
				margin: -1px;
				overflow: hidden;
				clip-path: inset(50%);
				white-space: nowrap;
			}
			#error {
				position: fixed;
				inset: auto 12px 12px 12px;
				display: none;
				padding: 10px 14px;
				border-radius: 10px;
				background: rgba(120, 30, 30, 0.85);
				color: #ffe8e8;
				font: 500 13px/1.4 system-ui, sans-serif;
				z-index: 3;
			}
			#error.show {
				display: block;
			}
		</style>
	</head>
	<body>
		<div id="app"></div>
		<div id="loading" role="status" aria-live="polite">
			<div class="loading__photo" aria-hidden="true"></div>
			<div class="loading__tint" aria-hidden="true"></div>
			<p class="loading__line" aria-hidden="true">
				<span class="word">quack</span>
				<span class="loading__dots"><span>.</span><span>.</span><span>.</span></span>
				<span class="word">quack</span>
			</p>
			<p class="visually-hidden">loading the pond</p>
		</div>
		<div id="error"></div>
		<script type="module" src="/src/main.ts"></script>
		<script>
			// If the module never boots (network, syntax, WebGL), surface it.
			setTimeout(() => {
				if (!window.__quackStarted) {
					const el = document.getElementById('error');
					el.textContent = 'the pond did not start — check the console, and make sure WebGL is available';
					el.classList.add('show');
				}
			}, 12000);
		</script>
	</body>
</html>