/* cntxt · cntxtlabs.co
   Type after nelson.co: system stack, one size, weight carries hierarchy,
   and no font-smoothing override, which is what keeps the weight in it.
   Colour after ia.net/writer. */

:root {
	--bg: #F7F7F7;
	--text: #222222;
	--muted: #A1A1AA;
	--rule: #D6D6D6;
	--blue: #00B2FF;
	--step: 60ms;
}

@media (prefers-color-scheme: dark) {
	:root {
		--bg: #070707;
		--text: #F0F0F0;
		--muted: #71717A;
		--rule: #2A2A2A;
		--blue: #00B2FF;
	}
}

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

html {
	background-color: var(--bg);
	font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	font-size: 15px;
	font-weight: 400;
	-webkit-text-size-adjust: 100%;
}

::selection {
	background-color: rgba(0, 178, 255, 0.22);
}

/* 600px of text. Footer sits at the bottom of the viewport whenever the
   page is too short to push it there itself. */

body {
	font-size: 1rem;
	color: var(--text);
	line-height: 1.6;
	text-align: left;
	margin: 0 auto;
	padding: 15em 1.5em 2em;
	max-width: calc(600px + 3em);
	min-height: 100vh;
	min-height: 100svh;
	display: flex;
	flex-direction: column;
}

@media (max-width: 34rem) {
	body {
		padding-top: 5em;
	}
}

/* Type. Two weights for the page, a third for the wordmark. */

h1,
h2,
h3,
p,
footer {
	font-size: 1rem;
}

h1 {
	margin-top: 2.5em;
	margin-bottom: 1.5em;
	font-weight: 500;
	color: var(--text);
}

h2 {
	margin-top: 2.5em;
	margin-bottom: 0.75em;
	font-weight: 500;
	color: var(--text);
}

p {
	margin-top: 0;
	margin-bottom: 1.2em;
}

.lead {
	margin-top: 3em;
}

strong {
	font-weight: 500;
}

/* Masthead. Identical on every page, heaviest thing on it. */

.title {
	margin-top: 0;
	margin-bottom: 0;
	font-weight: 700;
}

.sub {
	margin-top: 0;
	margin-bottom: 0;
}

/* Links. Heavier than the text, blue on hover. No underline. */

a:link,
a:visited {
	color: var(--text);
	font-weight: 500;
	text-decoration: none;
	transition: color 170ms ease;
}

a:hover,
a:focus-visible {
	color: var(--blue);
}

a:focus-visible {
	outline: none;
}

/* Reveals: text that unfolds on hover. The wordmark puts its vowels
   back, the subtitle thinks highly of the place, the footer counts
   from the beginning. */

.grow {
	display: inline-block;
	max-width: 0;
	opacity: 0;
	overflow: hidden;
	vertical-align: bottom;
	white-space: nowrap;
	transition: max-width 340ms cubic-bezier(0.22, 0.61, 0.36, 1), opacity 260ms ease;
}

.reveals:hover .grow,
.reveals:focus-visible .grow {
	max-width: 8ch;
	opacity: 1;
}

.reveals:hover .grow-wide,
.reveals:focus-visible .grow-wide {
	max-width: 40ch;
}

.strike {
	transition: text-decoration-color 200ms ease;
	text-decoration: line-through;
	text-decoration-color: transparent;
	text-decoration-thickness: 1px;
}

.reveals:hover .strike {
	text-decoration-color: currentColor;
}

@media (max-width: 34rem) {
	.grow-wide {
		display: none;
	}
}

.titlelink {
	font-weight: 700;
	position: relative;
}

/* The mark sits above the wordmark, out of the flow so nothing below it
   moves. It drops in, turns itself the right way up, then keeps bobbing
   for as long as you stay. */

.mark {
	position: absolute;
	left: 0;
	bottom: calc(100% + 0.5em);
	width: 1.7em;
	height: 1.7em;
	opacity: 0;
	pointer-events: none;
	transform: translateY(10px) scale(0.72) rotate(-150deg);
	transition: opacity 240ms ease, transform 560ms cubic-bezier(0.34, 1.4, 0.64, 1);
}

.titlelink:hover .mark,
.titlelink:focus-visible .mark {
	opacity: 1;
	transform: translateY(0) scale(1) rotate(0deg);
	animation: bob 2.4s ease-in-out 560ms infinite;
}

@keyframes bob {
	0%, 100% { translate: 0 0; }
	50% { translate: 0 -5px; }
}

.titlelink:link,
.titlelink:visited {
	color: var(--text);
}

.titlelink:hover,
.titlelink:focus-visible {
	color: var(--blue);
}

/* Nav. Home only. */

nav {
	margin-top: 2em;
	margin-bottom: 2em;
}

nav a {
	margin-right: 1.5em;
	font-weight: 400;
}

nav a:link,
nav a:visited {
	color: var(--muted);
}

nav a:hover {
	color: var(--blue);
}

nav a[aria-current="page"]:link,
nav a[aria-current="page"]:visited {
	color: var(--text);
	font-weight: 500;
}

nav a[aria-current="page"]:hover {
	color: var(--text);
}

/* Live metrics, inline in the sentence. Tabular figures hold each number's
   width steady while it counts, so the words after it do not shuffle. The
   mark and the number take the accent only when you point at them. */

.metric {
	white-space: nowrap;
}

.metric .metric-label {
	white-space: normal;
}

.metrics svg {
	width: 1.05em;
	height: 1.05em;
	margin-right: 0.35em;
	vertical-align: -0.16em;
	color: var(--text);
	transition: color 170ms ease;
}

.figure {
	display: inline-block;
	font-weight: 500;
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum" 1;
	text-align: left;
	transition: color 170ms ease;
}

.metric:hover svg,
.metric:hover .figure {
	color: var(--blue);
}

/* Project list. Name, then what it is. */

ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

.projects {
	margin-top: 3em;
}

.projects li {
	margin-bottom: 1.5em;
}

.projects .desc {
	display: block;
	margin-top: 0.1em;
}

/* Buttons. Square corners, a mark, and a small lift on hover. */

.btn {
	display: inline-flex;
	align-items: center;
	gap: 0.55em;
	margin-bottom: 1.2em;
	padding: 0.75em 1.15em;
	border-radius: 0;
	background-color: var(--text);
	font-weight: 500;
	line-height: 1;
	transition: background-color 200ms ease, color 200ms ease, transform 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.btn:link,
.btn:visited {
	color: var(--bg);
}

.btn:hover,
.btn:focus-visible {
	background-color: var(--blue);
	color: #ffffff;
	transform: translateY(-2px);
}

.btn:active {
	transform: translateY(0);
}

.btn svg {
	width: 1.05em;
	height: 1.05em;
	flex: none;
	margin-top: -0.1em;
}

/* Footer. Held to the bottom, and quieter than everything above it. */

footer {
	margin-top: auto;
	padding-top: 0.75em;
	border-top: 1px dashed var(--rule);
	color: var(--muted);
	text-align: left;
}

footer p {
	margin: 0;
}

/* Everything eases up on arrival. */

@keyframes fadeInFromBottom {
	from {
		opacity: 0;
		transform: translateY(0.5em);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

.reveal > * {
	animation: fadeInFromBottom 900ms ease forwards;
	opacity: 0;
}

.reveal > *:nth-child(1) { animation-delay: calc(0 * var(--step)); }
.reveal > *:nth-child(2) { animation-delay: calc(1 * var(--step)); }
.reveal > *:nth-child(3) { animation-delay: calc(2 * var(--step)); }
.reveal > *:nth-child(4) { animation-delay: calc(3 * var(--step)); }
.reveal > *:nth-child(5) { animation-delay: calc(4 * var(--step)); }
.reveal > *:nth-child(6) { animation-delay: calc(5 * var(--step)); }
.reveal > *:nth-child(7) { animation-delay: calc(6 * var(--step)); }
.reveal > *:nth-child(8) { animation-delay: calc(7 * var(--step)); }
.reveal > *:nth-child(n + 9) { animation-delay: calc(8 * var(--step)); }

@media (prefers-reduced-motion: reduce) {
	.reveal > * {
		animation: none;
		opacity: 1;
		transform: none;
	}

	.grow,
	.strike,
	a,
	.btn,
	.mark {
		transition: none;
	}

	.titlelink:hover .mark {
		animation: none;
	}

	.mark {
		transform: none;
	}

	.btn:hover {
		transform: none;
	}
}
