/* The home page: its sections, the comparison diagrams and the team card. The
pricing passes are pass.css. */

@layer tokens {
	:root {
		/* Service brand colours for the comparison diagram: in each theme, the
		nearest shade of the brand that clears WCAG AA as label text. */
		--service-redis: #ff4438;
		--service-postgres: #5e85f9;
		--service-nats: #27aae1;
		--service-eventstore: #5ab552;
		--service-backblaze: #fa4953;
	}

	:root[data-theme="light"] {
		/* The diagram's service colours, dark enough for their labels to clear
		WCAG AA on paper. */
		--service-redis: #b83128;
		--service-postgres: #395cc5;
		--service-nats: #186b8e;
		--service-eventstore: #387133;
		--service-backblaze: #c61a24;
	}
}

@layer components {
	/* Glass goes behind text that sits straight on background art: it darkens and
	blurs the art under it. Only the background color is set, so a component's own
	background image stays. */
	.glass {
		background-color: rgb(var(--ch-ink) / 72%);
		backdrop-filter: blur(8px) saturate(1.2);
	}
}

@layer pages {
	/* Headings, labels and one-line statements balance their lines; running
	text only avoids a stub last line. */
	.site-home {
		:is(h1, h2, h3, h4, figcaption, summary, .kicker, .label, .lede, .section-title, .team-lede) {
			text-wrap: balance;
		}

		p,
		li,
		blockquote {
			text-wrap: pretty;
		}
	}

	.site-hero {
		--split-side: minmax(0, 34rem);

		align-items: center;

		/* Its console takes 34rem, so the hero turns at 75rem, with the bar,
		rather than at the split's 60rem. */
		grid-template-columns: minmax(0, 1fr);

		@media (min-width: 75rem) {
			grid-template-columns: var(--split-main, minmax(0, 1fr)) var(--split-side);
		}

		/* The hero's type fits its column: <fit-text> sizes each line to fill it,
		and the cqi size is the fallback without JavaScript. The heading is a
		block, so each line measures the column rather than the longest line. */
		h1 {
			font-size: clamp(1.5rem, 11cqi, 4rem);
			line-height: 1.05;

			.hero-accent {
				color: var(--color-action);
				text-shadow: 0 0 18px rgb(var(--ch-action) / 35%);
			}
		}
	}

	/* <fit-text> sets white-space itself, so a line still wraps without
	JavaScript. */
	.hero-line {
		display: block;
		/* Never narrower than its column, so clientWidth is the room the line has
		to fill rather than the room its text happens to want. */
		inline-size: 100%;
		min-inline-size: 0;
	}

	.hero-copy {
		/* The unit the hero's type is measured in: cqi is 1% of this box. */
		container-type: inline-size;
		padding: var(--space-4);

		@media (min-width: 44rem) {
			padding: var(--space-5) var(--space-6);
		}
	}

	/* Both formats of a console card share one view-transition name, so the
	format selector's swap (its __viewtransition modifier) cross-fades them. */
	.query-result {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		gap: 0;
		view-transition-name: query-panel;
	}

	::view-transition-old(query-panel),
	::view-transition-new(query-panel) {
		animation-duration: 160ms;
	}

	.query-console > .tabs {
		align-self: center;
	}

	.query-format {
		display: flex;
		justify-content: center;
		border-block-start: 1px solid var(--color-line-low);
		padding-block-start: var(--space-3);
	}

	.site-quote {
		max-inline-size: 52rem;
		margin-inline: auto;
		font-size: clamp(1.2rem, 1rem + 1vw, 1.7rem);
	}

	.video {
		position: relative;
		display: grid;
		place-items: center;
		margin: 0;
		aspect-ratio: 16 / 9;
		overflow: hidden;
		cursor: pointer;

		/* The picture sits recessed in the panel: inset from the frame, with a dark
		upper lip, a lit lower edge and an inner shadow over it. */
		img,
		&::after {
			position: absolute;
			inset: var(--space-3);
			inline-size: calc(100% - 2 * var(--space-3));
			block-size: calc(100% - 2 * var(--space-3));
		}

		img {
			object-fit: cover;
			opacity: 0.6;
		}

		&::after {
			content: "";
			border: 1px solid var(--color-line-low);
			border-block-start: 2px solid rgb(var(--ch-shadow) / 70%);
			border-block-end-color: rgb(var(--ch-glow) / 40%);
			box-shadow:
				inset 0 6px 18px rgb(var(--ch-shadow) / 75%),
				inset 0 0 40px rgb(var(--ch-shadow) / 45%);
			pointer-events: none;
		}

		&:hover img {
			opacity: 0.75;
		}
	}

	.video-play {
		position: relative;
		z-index: 1;
		min-block-size: 4.5rem;
		min-inline-size: 4.5rem;

		.icon {
			inline-size: 1.8rem;
			block-size: 1.8rem;
		}
	}

	.demo {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		align-items: center;
		gap: var(--space-6);
		padding: var(--space-4);

		@media (min-width: 44rem) {
			padding: var(--space-6);
		}

		@media (min-width: 68rem) {
			grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
		}

		h2 {
			font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.6rem);
		}
	}

	.demo-logo {
		justify-self: center;
		inline-size: 9rem;
		block-size: auto;
		filter: drop-shadow(0 0 18px rgb(var(--ch-action) / 35%));
	}

	.demo-details {
		align-items: center;
		text-align: center;

		.stat {
			font-size: clamp(2.4rem, 2rem + 2vw, 4rem);
		}
	}

	/* A comparison pairs the argument with its system diagram. */
	.comparison {
		--split-side: minmax(0, 30rem);

		align-items: center;
		padding: var(--space-4);

		@media (min-width: 44rem) {
			padding: var(--space-6);
		}

		h2 {
			font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.6rem);
		}

		p {
			max-inline-size: 60ch;
			line-height: 1.7;
		}

		strong {
			color: var(--color-text-strong);
		}
	}

	/* System diagrams sit on the blueprint grid of .diagram. Routes are faint
	lines that take a service's color while it is active; the server warms to
	warning and runs hot in danger. */
	/* <service-diagram> (site/assets/rocket/service-diagram.js) is the element; it
	has no shadow root and renders nothing, so the diagram below is this page's own
	markup and these rules reach it. */
	.system-diagram {
		/* Every length in the drawing is a multiple of --u, so the diagram scales
		as a whole with its column: 27.2 units across its border, between a floor
		that fits a 320px phone and the 1rem it was drawn at. */
		--u: clamp(0.45rem, calc((100cqi - 4px) / 27.2), 1rem);

		container-type: inline-size;
		display: flex;
		align-items: center;
		justify-content: center;
		min-block-size: calc(20 * var(--u));
		overflow-x: auto;
		border: 1px solid var(--color-line);
		border-block-end: 2px solid var(--color-glow);
		padding: calc(1.5 * var(--u));
		background:
			repeating-linear-gradient(90deg, rgb(var(--ch-edge) / 9%) 0 1px, transparent 1px 24px),
			repeating-linear-gradient(rgb(var(--ch-edge) / 9%) 0 1px, transparent 1px 24px),
			radial-gradient(ellipse at 50% 100%, rgb(var(--ch-glow) / 18%), transparent 70%),
			rgb(var(--ch-ink) / 88%);
		box-shadow: 0 6px 18px -8px var(--color-glow);
	}

	.app-node {
		display: grid;
		flex: none;
		justify-items: center;
		gap: calc(0.5 * var(--u));
		inline-size: calc(8 * var(--u));
		color: var(--color-info);
		--track: 0.1em;
		font-size: calc(0.66 * var(--u));
		text-align: center;
	}

	.server-icon {
		inline-size: calc(3.5 * var(--u));
		block-size: calc(3.5 * var(--u));
		color: var(--color-text-dim);

		:is(rect, path):last-of-type {
			stroke: var(--color-info);
		}

		&.warm :is(rect, path) {
			stroke: var(--color-warning);
		}

		&.hot :is(rect, path) {
			stroke: var(--color-danger);
		}
	}

	.system-lines {
		flex: none;
		inline-size: calc(7 * var(--u));
		block-size: calc(14 * var(--u));
		margin-inline-start: calc(-1.5 * var(--u));

		svg {
			inline-size: 100%;
			block-size: 100%;
			overflow: visible;
		}

		line,
		polyline {
			fill: none;
			stroke: var(--color-line);
			stroke-width: 2;
			transition: stroke 120ms ease;
		}

		.route-activity.active {
			stroke: var(--active-route-color, var(--color-glow));
		}
	}

	.service-stack {
		display: grid;
		flex: 0 1 calc(11 * var(--u));
		gap: calc(0.5 * var(--u));
		min-inline-size: calc(8 * var(--u));
	}

	.service-node {
		--service-color: var(--color-glow);

		display: flex;
		align-items: center;
		gap: calc(0.75 * var(--u));
		min-block-size: calc(2.7 * var(--u));
		color: var(--color-text-dim);
		font-family: var(--font-data);
		font-size: calc(0.8 * var(--u));
		transition: color 120ms ease;

		&.active {
			color: var(--service-color);
		}
	}

	.service-icon {
		display: grid;
		flex: none;
		place-items: center;
		inline-size: calc(2.6 * var(--u));
		block-size: calc(2.6 * var(--u));
		border: 1px solid currentcolor;

		&::before {
			content: "";
			inline-size: calc(1.6 * var(--u));
			block-size: calc(1.6 * var(--u));
			background: currentcolor;
			mask: var(--service-icon) center / contain no-repeat;
		}
	}

	.redis {
		--service-color: var(--service-redis);
		--service-icon: url("/assets/icons/services/redis-fc830b00425ad2ae59cbbecb5c95214bfe9bcc9e8b890abcdd2cea426f017900.svg");
	}

	.postgres {
		--service-color: var(--service-postgres);
		--service-icon: url("/assets/icons/services/postgresql-45205af869a6c0963ec3dead930aca5ed55f917662f9c96558aa0ebd8c193381.svg");
	}

	.nats {
		--service-color: var(--service-nats);
		--service-icon: url("/assets/icons/services/nats-7faf50c7934f39ecc657a1a6ff4bc69f997fd7620c0a5fe0ceb259addae2db64.svg");
	}

	.eventstore {
		--service-color: var(--service-eventstore);
		--service-icon: url("/assets/icons/services/event-store-d9eca1ebc77469f25dccf57567c62a459fbde80dd5bcea6e95d1021f0eb4899b.svg");
	}

	.backblaze {
		--service-color: var(--service-backblaze);
		--service-icon: url("/assets/icons/services/backblaze-0b13bf00aebae137427fa54c80c39ef0efb1783728215a2e4dbff58ea2d43c8f.svg");
	}

	/* The Stardust side is gold: one service and its backup route. */
	.stardust-system .system-lines line {
		stroke: var(--color-action);
	}

	.stardust-services {
		gap: 0;
		margin-block-start: calc(-6 * var(--u));
		color: var(--color-action);

		.service-node:last-child,
		.backup-node {
			--service-color: var(--color-action-high);

			color: var(--color-action);
		}
	}

	.backup-route {
		display: block;
		inline-size: calc(2.6 * var(--u));
		block-size: calc(3 * var(--u));

		svg {
			inline-size: 100%;
			block-size: 100%;
		}

		line {
			stroke: var(--color-line);
			stroke-width: 2;
		}

		&.active line {
			stroke: var(--color-action);
		}
	}

	.stardust-icon {
		flex: none;
		inline-size: calc(2.6 * var(--u));
		block-size: calc(2.6 * var(--u));
		border: 1px solid currentcolor;
		padding: calc(0.25 * var(--u));
		background: var(--color-deep);
	}

	/* The capability ledger: ruled rows of index, heading and explanation. */
	.ledger {
		margin-block-start: var(--space-5);
		border-block-start: 1px solid var(--color-line);
		padding: 0;
		list-style: none;

		li {
			display: grid;
			grid-template-columns: 3rem minmax(0, 1fr);
			align-items: baseline;
			gap: var(--space-2) var(--space-5);
			border-block-end: 1px solid var(--color-line-low);
			padding: var(--space-4) var(--space-3);

			@media (min-width: 60rem) {
				grid-template-columns: 4rem minmax(12rem, 0.7fr) minmax(0, 1.3fr);
			}

			&:hover {
				background: rgb(var(--ch-edge) / 8%);
			}
		}

		h3 {
			font-size: 1rem;
		}

		p {
			grid-column: 2;
			color: var(--color-text-dim);

			@media (min-width: 60rem) {
				grid-column: auto;
			}
		}
	}

	.ledger-index {
		color: var(--color-action);
		font-family: var(--font-data);
		font-size: 0.8rem;
	}

	/* Pricing: the introduction, the alpha note, then one license pass per tier
	(the account page's .pass) and the Enterprise card, full width. */
	.pricing {
		gap: var(--space-4);
	}

	/* Glass behind the pricing introduction that fades out downward, so the text
	reads over the art without a hard edge. */
	.pricing-intro {
		position: relative;
		isolation: isolate;
		align-items: center;
		padding: var(--space-4) var(--space-4) var(--space-5);

		@media (min-width: 44rem) {
			padding: var(--space-5) var(--space-5) var(--space-6);
		}

		&::before {
			content: "";
			position: absolute;
			z-index: -1;
			inset: 0;
			border-block-start: 2px solid var(--color-action);
			background: rgb(var(--ch-ink) / 78%);
			backdrop-filter: blur(8px) saturate(1.2);
			mask-image: linear-gradient(180deg, black 55%, transparent);
		}
	}

	/* The team card, drawn as a Datastar panel in the Datastar logo's palette,
	with a light variant of the same ramp. Its frame is its background showing
	through the padding, clipped into pixel steps. */
	.team-story {
		/* The rocket's palette, read out of datastar-logo.svg. */
		--ds-void: #172038;
		--ds-deep: #253a5e;
		--ds-line: #3c5e8b;
		--ds-blue: #4f8fba;
		--ds-cyan: #73bed3;
		--ds-pale: #a4dddb;
		--ds-gold: #e8c170;
		--ds-flame: #cf573c;
		/* The grid the rocket is drawn on, and the lede's ink: both follow the
		ground under them, so the light ramp below can move them with it. */
		--ds-grid: rgb(255 255 255 / 3%);
		--ds-ink: #f2f0e5;
		/* The wordmark, in the homepage's --orange-5. */
		--ds-mark: oklch(0.63 0.13 63.23);

		/* The same ramp on paper: the hues and their order are the logo's, lifted
		so the darkest step is the ground and the lightest is the ink. Every pair
		the card sets clears WCAG AA, the lowest being a link at 5.21. */
		:root[data-theme="light"] & {
			--ds-void: #eaf1f6;
			--ds-deep: #d7e4ef;
			--ds-line: #b9cfe0;
			--ds-blue: #2f6a91;
			--ds-cyan: #186b8e;
			--ds-pale: #1b2f4a;
			--ds-gold: #6f5310;
			--ds-flame: #a33a24;
			--ds-grid: rgb(27 47 74 / 6%);
			--ds-ink: #1b2f4a;
			/* Two steps down the same hue: the orange as written reads at 2.81 on
			the light band, and the band cannot lift to meet it without going the
			colour of the ground and flattening the card. */
			--ds-mark: oklch(0.59 0.13 63.23);
		}
		/* One pixel of the drawing, at the size the card draws it. */
		--px: 6px;

		/* Two columns, the identity on the lighter ground beside the argument,
		centred and held to 60rem so the argument keeps a readable measure. */
		display: grid;
		grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
		gap: var(--px);
		max-inline-size: 60rem;
		margin-inline: auto;
		border-radius: 0;
		padding: var(--px);
		background: var(--ds-line);
		color: var(--ds-pale);
		clip-path: polygon(
			0 var(--px),
			var(--px) var(--px),
			var(--px) 0,
			calc(100% - var(--px)) 0,
			calc(100% - var(--px)) var(--px),
			100% var(--px),
			100% calc(100% - var(--px)),
			calc(100% - var(--px)) calc(100% - var(--px)),
			calc(100% - var(--px)) 100%,
			var(--px) 100%,
			var(--px) calc(100% - var(--px)),
			0 calc(100% - var(--px))
		);

		a {
			color: var(--ds-cyan);
			text-decoration-color: var(--ds-blue);
		}

		strong {
			color: var(--ds-gold);
		}
	}

	/* The mark and the sentence it belongs to, stacked and centred on the
	lighter ground; cqi sizes the wordmark against this column. */
	.team-identity {
		container-type: inline-size;

		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: var(--space-4);
		padding: var(--space-5);
		background: var(--ds-deep);
		text-align: center;
	}

	/* The Datastar wordmark, set in type as data-star.dev sets it, with the
	rocket above it so the wordmark sizes itself against the whole column. */
	.datastar-mark {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: var(--space-3);
		text-decoration: none;
	}

	.datastar-wordmark {
		justify-items: center;

		/* One size, measured against the column, drives both lines; the wordmark
		never wraps, so it shrinks. DATASTAR fits a column at 8.06cqi. */
		font-size: clamp(0.62rem, 7.8cqi, 1.5rem);

		display: grid;
		gap: 0.15em;
		/* Tilted back, the way the homepage sets it. It comes off on a narrow card,
		   where the type is small enough that the perspective only blurs it. */
		transform: perspective(40rem) rotateX(14deg);
		transform-origin: center bottom;
		user-select: none;
	}

	.datastar-name,
	.datastar-tagline {
		font-family: "Audiowide", var(--font-display);
		line-height: 1;
		text-transform: uppercase;
		white-space: nowrap;
	}

	.datastar-name {
		color: var(--ds-mark);
		font-size: 1.9em;
		letter-spacing: 0.02em;
		text-shadow: 0 2px 0 rgb(var(--ch-shadow) / 35%);
	}

	.datastar-tagline {
		color: var(--ds-ink);
		font-size: 0.64em;
		letter-spacing: 0.04em;
	}

	/* Pixel art, drawn without smoothing: the rocket is a 24 unit grid, and a
	   browser's default interpolation turns that to mush when it is scaled up. */
	.datastar-mark img {
		flex: none;
		/* Whole steps of the 24 unit grid, so the pixels stay square. */
		inline-size: clamp(24px, 14cqi, 56px);
		block-size: clamp(24px, 14cqi, 56px);
		image-rendering: pixelated;
	}

	/* The rocket flies, or holds still for a reader who asked for less motion. */
	.datastar-mark .rocket-static {
		display: none;
	}

	@media (prefers-reduced-motion: reduce) {
		.datastar-mark .rocket-animated {
			display: none;
		}

		.datastar-mark .rocket-static {
			display: block;
			image-rendering: auto;
		}
	}

	/* The Stardust sentence beside the mark, in Stardust's display face, sized as
	a statement and wrapping to a short block. */
	.team-lede {
		margin: 0;
		color: var(--ds-ink);
		font-family: var(--font-display);
		font-size: clamp(0.95rem, 5.2cqi, 1.35rem);
		line-height: 1.35;
		text-wrap: balance;
	}

	@media (max-width: 43.99rem) {
		.datastar-wordmark {
			transform: none;
		}
	}

	.team-body {
		padding: var(--space-5);
		/* The grid the rocket is drawn on, at the size the card draws it. */
		background:
			repeating-linear-gradient(90deg, var(--ds-grid) 0 1px, transparent 1px calc(var(--px) * 4)),
			repeating-linear-gradient(var(--ds-grid) 0 1px, transparent 1px calc(var(--px) * 4)),
			var(--ds-void);

		p {
			color: var(--ds-pale);
		}

		/* The first line is the claim and the rest is the case for it, so it opens
		   a step above them. */
		p:first-child {
			color: var(--ds-ink);
			font-size: 1.1rem;
		}

		/* Block rather than the stack's flex column, so it can set in more than
		   one column; the paragraphs carry their own spacing instead of a gap. */
		.argument {
			display: block;
			max-inline-size: none;
		}

		.argument > p {
			margin: 0 0 var(--space-4);
			break-inside: avoid;
		}

		.argument > p:last-child {
			margin-block-end: 0;
		}
	}

	/* Below the width where two columns of anything are readable, the identity
	   becomes the card's header and the argument follows it. */
	@media (max-width: 47.99rem) {
		.team-story {
			grid-template-columns: minmax(0, 1fr);
		}
	}

	.faq {
		--split-main: minmax(0, 0.6fr);
		--split-side: minmax(0, 1.4fr);

		border-block: 1px solid var(--color-line-low);
		padding: var(--space-4);

		@media (min-width: 44rem) {
			padding: var(--space-6);
		}

		details {
			border-block-start: 1px solid var(--color-line-low);

			&:last-child {
				border-block-end: 1px solid var(--color-line-low);
			}

			p {
				max-inline-size: 45rem;
				padding: 0 var(--space-2) var(--space-4);

				@media (min-width: 44rem) {
					padding: 0 var(--space-6) var(--space-4) var(--space-2);
				}
				color: var(--color-text-dim);
			}
		}

		summary {
			display: grid;
			grid-template-columns: minmax(0, 1fr) auto;
			gap: var(--space-4);
			padding: var(--space-4) var(--space-2);
			color: var(--color-text-strong);
			cursor: pointer;
			user-select: none;
			list-style: none;

			&::-webkit-details-marker {
				display: none;
			}

			&::after {
				content: "+";
				color: var(--color-action);
				font-family: var(--font-data);
			}

			&:hover {
				color: var(--color-sand);
			}
		}

		details[open] summary::after {
			content: "\2212";
		}
	}

	.site-footer {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: var(--space-4);
		border-block-start: 1px solid var(--color-line-low);
		padding-block-start: var(--space-5);

		a {
			--track: 0.1em;
			color: var(--color-text-dim);
			font-size: 0.66rem;
			text-decoration: none;

			&:hover {
				color: var(--color-info);
			}
		}
	}
}
