/* Signed-out / booting / pairing: a plain block — those screens size themselves. */
root-app {
	display: block;
	min-height: 100dvh;

	/* Signed in, the host IS the app shell (no wrapper): banners / scrollable
	   page / bottom nav. Only <main> scrolls, so the nav is pinned by the grid
	   rather than by position: fixed. */
	&[phase="ready"] {
		display: grid;
		grid-template-rows: auto 1fr auto;
		grid-template-areas: "banner" "page" "nav";
		height: 100dvh;
		min-height: 0;
	}

	& > .offline-banner { grid-area: banner; }
	& > main { grid-area: page; }
	& > .bottom-nav { grid-area: nav; }
}

main {
	display: block;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior-y: contain;

	/* The routed page fills the scroll area, so a page can centre or stretch its
	   content against the visible height (height: 100% needs a resolved parent). */
	& > * {
		display: block;
		box-sizing: border-box;
		height: 100%;
		max-width: 1100px;
		margin: 0 auto;
		padding: var(--space-m) var(--space-m) var(--space-xl);
	}
}

.auth-loading {
	position: fixed;
	inset: 0;
	display: grid;
	place-items: center;

	&::after {
		content: "";
		width: 38px;
		height: 38px;
		border: 3px solid var(--surface-3);
		border-top-color: var(--color-primary);
		border-radius: 50%;
		animation: spin 0.8s linear infinite;
	}
}

@keyframes spin {
	to {
		transform: rotate(360deg);
	}
}

.offline-banner {
	background: var(--color-primary-grad);
	color: #fff;
	text-align: center;
	padding: var(--space-xs) var(--space-s);
	font: var(--font-body-small-semibold);
}

/* ─── Bottom navigation ──────────────────────────────────────────────────── */
.bottom-nav {
	height: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px));
	padding-bottom: env(safe-area-inset-bottom, 0px);
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: minmax(0, 1fr);
	background: var(--nav-bg);
	backdrop-filter: blur(16px);
	border-top: 1px solid var(--border);

	& a {
		display: grid;
		grid-template-rows: auto auto;
		justify-items: center;
		align-content: center;
		gap: var(--space-2xs);
		color: var(--text-faint);
		font: var(--font-body-xsmall-regular);
		transition: color 0.15s;

		&.active { color: var(--text); }
		&.active .icon { color: var(--color-primary); }
	}

	& .icon { font-size: 24px; }
}

/* ─── Sync bar ───────────────────────────────────────────────────────────── */
/* Indeterminate, pinned to the top edge while a sync runs. It fades in after a
   beat so the usual sub-second sync doesn't flicker it. */
.sync-bar {
	position: fixed;
	inset-inline: 0;
	top: 0;
	z-index: 60;
	height: 3px;
	overflow: hidden;
	pointer-events: none;
	opacity: 0;
	animation: fade-in-bar 0.2s ease 0.4s forwards;

	&::after {
		content: "";
		position: absolute;
		inset-block: 0;
		width: 40%;
		background: var(--color-primary);
		border-radius: 3px;
		animation: sync-slide 1.2s ease-in-out infinite;
	}

	@media (prefers-reduced-motion: reduce) {
		&::after {
			width: 100%;
			animation: none;
		}
	}
}

@keyframes fade-in-bar {
	to {
		opacity: 1;
	}
}

@keyframes sync-slide {
	from {
		inset-inline-start: -40%;
	}
	to {
		inset-inline-start: 100%;
	}
}
