/* ryffle.com, the coming-soon page and its 404. One file, no fonts, no images but the mark.
   The colours are the product's own (packages/ui/src/styles.css): its background, text, muted text, surface, border,
   input line, ring and accent, light and dark. The accent is the mark's indigo (apps/web/public/icon.svg). */

:root {
	color-scheme: light;
	--bg: oklch(0.992 0.002 250);
	--fg: oklch(0.21 0.02 255);
	--muted-fg: oklch(0.5 0.02 255);
	--surface: oklch(1 0 0);
	--border: oklch(0.915 0.006 250);
	--line: oklch(0.88 0.008 250);
	--place: oklch(0.8 0.012 255);
	--ring: oklch(0.58 0.17 275);
	--accent: oklch(0.52 0.19 275);
	--accent-soft: oklch(0.52 0.19 275 / 0.1);
	--glow: oklch(0.52 0.19 275 / 0.09);
	--mark: oklch(0.52 0.19 275);
	--sans:
		ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI", Roboto,
		"Helvetica Neue", Arial, sans-serif;
}

@media (prefers-color-scheme: dark) {
	:root {
		color-scheme: dark;
		--bg: oklch(0.17 0.012 260);
		--fg: oklch(0.94 0.005 250);
		--muted-fg: oklch(0.7 0.015 255);
		--surface: oklch(0.215 0.014 260);
		--border: oklch(0.32 0.015 260);
		--line: oklch(0.34 0.016 260);
		--place: oklch(0.44 0.018 260);
		--ring: oklch(0.7 0.15 275);
		--accent: oklch(0.7 0.14 275);
		--accent-soft: oklch(0.7 0.14 275 / 0.16);
		--glow: oklch(0.6 0.17 275 / 0.13);
	}
}

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	background: var(--bg);
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

body {
	margin: 0;
	min-height: 100svh;
	background: radial-gradient(56rem 40rem at 80% 22rem, var(--glow), transparent 70%), var(--bg);
	color: var(--fg);
	font: 400 1rem / 1.5 var(--sans);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

a {
	color: var(--accent);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.22em;
}

a:hover {
	text-decoration-thickness: 2px;
}

:focus-visible {
	outline: 2px solid var(--ring);
	outline-offset: 3px;
	border-radius: 4px;
}

.page {
	display: grid;
	grid-template-rows: auto 1fr auto;
	min-height: 100svh;
	max-width: 80rem;
	margin: 0 auto;
	padding-inline: max(1rem, env(safe-area-inset-left)) max(1rem, env(safe-area-inset-right));
}

@media (min-width: 40rem) {
	.page {
		padding-inline: clamp(1.5rem, 4vw, 3rem);
	}
}

@media (min-width: 100rem) {
	.page {
		max-width: 90rem;
	}
}

/* The mark and the name. */

.top {
	padding-block: clamp(1.25rem, 3vw, 2.25rem);
}

.brand {
	display: inline-flex;
	align-items: center;
	gap: 0.625rem;
	margin: 0;
	font-size: 1.1875rem;
	font-weight: 650;
	letter-spacing: -0.015em;
}

.mark {
	display: block;
	flex: none;
}

.mark-tile {
	fill: var(--mark);
}

.mark-ring {
	stroke: #fff;
}

/* The promise, with the motif beside it; on a phone the motif comes under the words. On a desktop it fills the first
   screen, so the two sections after it start below the fold. */

.hero {
	display: grid;
	align-content: center;
	align-items: center;
	gap: clamp(2.5rem, 5vw, 4rem);
	padding-block: clamp(1.5rem, 6vw, 4rem) clamp(3.5rem, 8vw, 6rem);
}

@media (min-width: 62rem) {
	.hero {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
		min-height: calc(100svh - 9rem);
	}
}

.soon {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	margin: 0 0 clamp(1.25rem, 3vw, 1.75rem);
	padding: 0.3125rem 0.75rem 0.3125rem 0.625rem;
	border: 1px solid var(--border);
	border-radius: 999px;
	background: var(--surface);
	font-size: 0.875rem;
	font-weight: 550;
	line-height: 1.4;
}

.soon-dot {
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--accent);
	box-shadow: 0 0 0 3px var(--accent-soft);
}

h1 {
	margin: 0;
	font-size: clamp(2.5rem, 1.4rem + 3.6vw, 5rem);
	font-weight: 700;
	line-height: 1.03;
	letter-spacing: -0.042em;
	text-wrap: balance;
}

.h1-accent {
	color: var(--accent);
	white-space: nowrap;
}

.lead {
	max-width: 33rem;
	margin: clamp(1.25rem, 3vw, 1.75rem) 0 0;
	color: var(--muted-fg);
	font-size: clamp(1.125rem, 1rem + 0.45vw, 1.3125rem);
	line-height: 1.55;
	text-wrap: pretty;
}

/* Things finding their place. */

.motif svg {
	display: block;
	width: 100%;
	height: auto;
	overflow: visible;
}

.lanes rect {
	fill: var(--surface);
	stroke: var(--border);
	stroke-width: 1.5;
}

.wires path {
	stroke: var(--line);
}

/* The way in fades up from nothing: things arrive from outside the picture. */
.wires .wire-in {
	stroke: url(#arriving);
}
.fade-from {
	stop-color: var(--line);
	stop-opacity: 0;
}
.fade-to {
	stop-color: var(--line);
}

.places circle {
	stroke: var(--place);
}

.halo {
	stroke: var(--accent);
	opacity: 0;
}

.gate {
	fill: var(--surface);
	stroke: var(--accent);
}

.approve-node {
	fill: var(--surface);
	stroke: var(--accent);
}

.approve-tick {
	stroke: var(--accent);
	stroke-dasharray: 19;
}

.item {
	fill: var(--accent);
	offset-rotate: 0deg;
	transform-box: fill-box;
	transform-origin: center;
}

/* The three ways from the decision, the same for each item in that lane: the first, to the place after approval. */
.item-0,
.item-3 {
	offset-path: path("M24 210 H217 C275 210 275 90 333 90 H505");
}
.item-1,
.item-4 {
	offset-path: path("M24 210 H505");
}
.item-2,
.item-5 {
	offset-path: path("M24 210 H217 C275 210 275 330 333 330 H505");
}

/* Still (reduced motion, or before the animation starts): the whole story at once. Two items in their places, one
   waiting at the approval, one on its way, one at the decision, one coming in. */
.item-0,
.item-1 {
	offset-distance: 100%;
}
.item-2 {
	offset-distance: 466.55px;
}
.item-3 {
	offset-distance: 434.55px;
}
.item-4 {
	offset-distance: 176px;
}
.item-5 {
	offset-distance: 80px;
}
.halo-a,
.halo-b {
	opacity: 1;
}

/* Moving: an item every 2.5 s, each taking 15 s from coming in to settling. Lengths along the ways are in px of the
   drawing: 176 to the decision's middle, 434.55 to where the approval lane waits (the curve is 176.55 long). The
   decision lights as each item passes (every 2.5 s), the approval as its lane's items wait (every 7.5 s), and a place
   as its lane's items arrive (every 7.5 s); each runs on its first item's delay so they stay in step. */
@media (prefers-reduced-motion: no-preference) {
	.motif .item {
		opacity: 0;
		animation: travel 15s infinite both;
	}
	.item-0,
	.item-3 {
		animation-name: travel-approve;
	}
	.item-1 {
		animation-delay: -2.5s;
	}
	.item-2 {
		animation-delay: -5s;
	}
	.item-3 {
		animation-delay: -7.5s;
	}
	.item-4 {
		animation-delay: -10s;
	}
	.item-5 {
		animation-delay: -12.5s;
	}

	.gate {
		animation: decide 2.5s infinite both;
	}

	.approve-node {
		stroke: var(--line);
		animation: approve-node 7.5s infinite both;
	}
	.approve-tick {
		stroke-dashoffset: 19;
		opacity: 0;
		animation: approve-tick 7.5s infinite both;
	}

	.halo-a,
	.halo-b,
	.halo-c {
		opacity: 0;
	}
	.halo-a {
		animation: settle-a 7.5s infinite both;
	}
	.halo-b {
		animation: settle 7.5s -2.5s infinite both;
	}
	.halo-c {
		animation: settle 7.5s -5s infinite both;
	}
}

@keyframes travel {
	0% {
		offset-distance: 0;
		opacity: 0;
		transform: scale(1);
		animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
	}
	5% {
		opacity: 1;
	}
	18% {
		offset-distance: 176px;
		animation-timing-function: linear;
	}
	24% {
		offset-distance: 176px;
		animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1);
	}
	76% {
		offset-distance: 100%;
		opacity: 1;
		transform: scale(1);
	}
	88% {
		offset-distance: 100%;
		opacity: 1;
		transform: scale(1);
	}
	96%,
	100% {
		offset-distance: 100%;
		opacity: 0;
		transform: scale(0.5);
	}
}

@keyframes travel-approve {
	0% {
		offset-distance: 0;
		opacity: 0;
		transform: scale(1);
		animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
	}
	5% {
		opacity: 1;
	}
	18% {
		offset-distance: 176px;
		animation-timing-function: linear;
	}
	24% {
		offset-distance: 176px;
		animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1);
	}
	52% {
		offset-distance: 434.55px;
		animation-timing-function: linear;
	}
	64% {
		offset-distance: 434.55px;
		animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1);
	}
	80% {
		offset-distance: 100%;
		opacity: 1;
		transform: scale(1);
	}
	90% {
		offset-distance: 100%;
		opacity: 1;
		transform: scale(1);
	}
	97%,
	100% {
		offset-distance: 100%;
		opacity: 0;
		transform: scale(0.5);
	}
}

@keyframes decide {
	0%,
	4% {
		stroke: var(--place);
		fill: var(--surface);
	}
	12%,
	40% {
		stroke: var(--accent);
		fill: var(--surface);
	}
	60%,
	100% {
		stroke: var(--place);
		fill: var(--surface);
	}
}

@keyframes approve-node {
	0%,
	6% {
		stroke: var(--line);
	}
	12%,
	30% {
		stroke: var(--accent);
	}
	44%,
	100% {
		stroke: var(--line);
	}
}

@keyframes approve-tick {
	0%,
	12% {
		stroke-dashoffset: 19;
		opacity: 0;
	}
	14% {
		stroke-dashoffset: 19;
		opacity: 1;
		animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
	}
	22%,
	32% {
		stroke-dashoffset: 0;
		opacity: 1;
	}
	44%,
	100% {
		stroke-dashoffset: 0;
		opacity: 0;
	}
}

/* A place lights as an item arrives: at 60% of its 7.5 s for the approval lane, 52% for the others. */
@keyframes settle-a {
	0%,
	56% {
		opacity: 0;
	}
	62%,
	80% {
		opacity: 1;
	}
	94%,
	100% {
		opacity: 0;
	}
}

@keyframes settle {
	0%,
	48% {
		opacity: 0;
	}
	54%,
	76% {
		opacity: 1;
	}
	90%,
	100% {
		opacity: 0;
	}
}

/* The two sections after the promise: who stays in control, and work that has to be right. A heading a step under the
   h1, its line in the muted colour, and a small drawing of its own on a card. */

.part {
	display: grid;
	align-items: center;
	gap: clamp(2rem, 5vw, 5rem);
	padding-block: clamp(4.5rem, 10vw, 8.5rem);
	border-top: 1px solid var(--border);
}

@media (min-width: 56rem) {
	.part {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	}
	.part-flip .detail {
		order: -1;
	}
}

h2 {
	margin: 0;
	font-size: clamp(1.75rem, 1.1rem + 2.1vw, 2.875rem);
	font-weight: 680;
	line-height: 1.1;
	letter-spacing: -0.032em;
	text-wrap: balance;
}

/* A heading of two sentences breaks between them, never inside one while it fits. */
h2 .line {
	display: inline-block;
}

.part .lead {
	margin-top: clamp(1rem, 2.5vw, 1.5rem);
}

.detail {
	padding: clamp(1rem, 3vw, 2rem);
	border: 1px solid var(--border);
	border-radius: 1.5rem;
	background: var(--surface);
}

.detail svg {
	display: block;
	width: 100%;
	height: auto;
}

/* A name on it. Still: the item in its place, approved, and the person's tag lit. */
.signed-by {
	stroke: var(--accent);
}
.tag-card {
	fill: var(--bg);
	stroke: var(--accent);
}
.tag-avatar {
	fill: var(--accent-soft);
}
.tag-person {
	stroke: var(--accent);
}
.tag-name {
	fill: var(--place);
}
.tag-role {
	fill: var(--line);
}
.wires .wire-in-2 {
	stroke: url(#arriving-2);
}
.place {
	stroke: var(--place);
}
.signed-node {
	fill: var(--surface);
	stroke: var(--accent);
}
.signed-tick {
	stroke: var(--accent);
	stroke-dasharray: 19;
}
.signed-item {
	offset-path: path("M24 150 H440");
	offset-distance: 100%;
}
.halo.signed-halo {
	opacity: 1;
}

/* Exactly in place. Still: every item in the middle of its ring. */
.marks path {
	stroke: var(--line);
}

/* Moving. The signed item comes in, waits before the approval (191 px along), the tag lights and the tick is drawn, and
   then it goes on to its place: 9 s round. Each exact item comes down into its ring 0.7 s after the one before: 10 s. */
@media (prefers-reduced-motion: no-preference) {
	.signed-item {
		opacity: 0;
		animation: signed 9s infinite both;
	}
	.signed-node {
		stroke: var(--line);
		animation: signed-node 9s infinite both;
	}
	.signed-tick {
		opacity: 0;
		stroke-dashoffset: 19;
		animation: signed-tick 9s infinite both;
	}
	.tag-card {
		stroke: var(--border);
		animation: signed-tag 9s infinite both;
	}
	.signed-by {
		stroke: var(--line);
		animation: signed-by 9s infinite both;
	}
	.halo.signed-halo {
		opacity: 0;
		animation: signed-halo 9s infinite both;
	}

	.exact-item {
		opacity: 0;
		animation: exact 10s infinite both;
	}
	.exact-halo {
		animation: exact-halo 10s infinite both;
	}
	.exact-2 {
		animation-delay: 0.7s;
	}
	.exact-3 {
		animation-delay: 1.4s;
	}
	.exact-4 {
		animation-delay: 2.1s;
	}
}

@keyframes signed {
	0% {
		offset-distance: 0;
		opacity: 0;
		transform: scale(1);
		animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
	}
	6% {
		opacity: 1;
	}
	30% {
		offset-distance: 191px;
		animation-timing-function: linear;
	}
	58% {
		offset-distance: 191px;
		animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1);
	}
	80%,
	90% {
		offset-distance: 100%;
		opacity: 1;
		transform: scale(1);
	}
	97%,
	100% {
		offset-distance: 100%;
		opacity: 0;
		transform: scale(0.5);
	}
}

@keyframes signed-node {
	0%,
	28% {
		stroke: var(--line);
	}
	34%,
	60% {
		stroke: var(--accent);
	}
	70%,
	100% {
		stroke: var(--line);
	}
}

@keyframes signed-tick {
	0%,
	36% {
		stroke-dashoffset: 19;
		opacity: 0;
	}
	38% {
		stroke-dashoffset: 19;
		opacity: 1;
		animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
	}
	46%,
	88% {
		stroke-dashoffset: 0;
		opacity: 1;
	}
	96%,
	100% {
		stroke-dashoffset: 0;
		opacity: 0;
	}
}

@keyframes signed-tag {
	0%,
	34% {
		stroke: var(--border);
	}
	42%,
	88% {
		stroke: var(--accent);
	}
	96%,
	100% {
		stroke: var(--border);
	}
}

@keyframes signed-by {
	0%,
	32% {
		stroke: var(--line);
	}
	40%,
	88% {
		stroke: var(--accent);
	}
	96%,
	100% {
		stroke: var(--line);
	}
}

@keyframes signed-halo {
	0%,
	78% {
		opacity: 0;
	}
	84%,
	90% {
		opacity: 1;
	}
	98%,
	100% {
		opacity: 0;
	}
}

@keyframes exact {
	0% {
		opacity: 0;
		transform: translateY(-84px);
		animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
	}
	4% {
		opacity: 1;
	}
	22%,
	80% {
		opacity: 1;
		transform: translateY(0);
	}
	90%,
	100% {
		opacity: 0;
		transform: translateY(0);
	}
}

@keyframes exact-halo {
	0%,
	18% {
		opacity: 0;
	}
	23% {
		opacity: 1;
	}
	44%,
	100% {
		opacity: 0;
	}
}

/* The foot. */

.foot {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: 0.5rem 1.5rem;
	padding-block: 1.5rem max(1.5rem, env(safe-area-inset-bottom));
	border-top: 1px solid var(--border);
	color: var(--muted-fg);
	font-size: 0.9375rem;
}

.foot p {
	margin: 0;
}

/* The 404. */

.lost h1 {
	font-size: clamp(2.25rem, 1.5rem + 3.2vw, 3.75rem);
}

.lost .lead a {
	font-weight: 550;
}
