/*!
Theme Name: Berns Lab
Theme URI: https://bernardposniak.com/
Author: Bernard Posniak
Author URI: https://bernardposniak.com/
Description: A loud, playful laboratory theme for an AI and web development lab. Six-hue palette, oversized variable type, 3D tilt and parallax, a cursor that reacts, and achievements to find. Project board with a server-side uptime sentinel, spec-sheet project pages, stack taxonomy, full RTL support, self-hosted OFL fonts, no external CDNs, no framework runtime, no build step.
Version: 2.2.0
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 8.1
License: GNU General Public License v2 or later
License URI: LICENSE
Text Domain: berns-lab
Tags: custom-logo, custom-menu, featured-images, translation-ready, rtl-language-support, block-styles, wide-blocks, threaded-comments

Berns Lab is based on Underscores https://underscores.me/, (C) 2012-2024 Automattic, Inc.
Underscores is distributed under the terms of the GNU GPL v2 or later.

Bricolage Grotesque and Space Grotesk are bundled under the SIL Open Font
License 1.1, see assets/fonts/. They are self-hosted, subset to Latin, and
carry a unicode-range so Hebrew falls through to the system stack untouched.

DESIGN SYSTEM, six hues, and the one rule that keeps them legible
------------------------------------------------------------------
	#B8FF2E lime    #22E0F0 cyan    #A06CFF violet
	#FF4FA3 pink    #FF8A2B orange  #FFD23F yellow

A HUE IS A FILL. Ink sits on it, never the reverse. Every one of the six
clears 5.4:1 with ink text on top (lime reaches 15.6:1), while the same hues
as text on cream land between 1.2:1 and 3.5:1, unusable. So the loud colour
does the shouting as a surface and the type stays ink.

Where a hue genuinely must be text, a link, an eyebrow, it resolves through
--<hue>-text, which is the raw hue on the dark ground (8.7:1 or better) and a
measured darker twin on cream (all six ≥ 4.75:1). One token, two schemes, no
guessing at the call site.

Loud does not mean low-contrast. Body text is 18:1 on both grounds. The colour
is in the surfaces, the shadows and the motion.

MOTION
Everything moves on a spring, cubic-bezier(.34, 1.56, .64, 1), and every bit
of it collapses under prefers-reduced-motion: no float, no tilt, no parallax,
no marquee, no preloader. The page is complete and usable with JavaScript off
and motion disabled; all of this is decoration layered on working HTML.
*/

/*--------------------------------------------------------------
>>> TABLE OF CONTENTS:
----------------------------------------------------------------
# Fonts
# Tokens
# Reset
# Base typography
# Decor: blobs, stickers, marquee
# Layout
# Header & navigation
# Hero
# Sentinel
# Project grid & cards
# Project single
# Notes & archives
# Forms & buttons
# Comments
# Blocks & alignments
# Footer
# Preloader, cursor, toasts, achievements
# Accessibility & utilities
--------------------------------------------------------------*/

/*--------------------------------------------------------------
# Fonts
--------------------------------------------------------------*/
@font-face {
	font-family: "Bricolage Grotesque";
	src: url("assets/fonts/bricolage-var.woff2") format("woff2-variations");
	font-weight: 200 800;
	font-stretch: 75% 100%;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+2074, U+20AC, U+2122, U+2190-2193, U+2212, U+2215;
}

@font-face {
	font-family: "Space Grotesk";
	src: url("assets/fonts/space-grotesk-var.woff2") format("woff2-variations");
	font-weight: 300 700;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+2074, U+20AC, U+2122, U+2190-2193, U+2212, U+2215;
}

/*--------------------------------------------------------------
# Tokens
--------------------------------------------------------------*/
:root {
	--lime: #b8ff2e;
	--cyan: #22e0f0;
	--violet: #a06cff;
	--pink: #ff4fa3;
	--orange: #ff8a2b;
	--yellow: #ffd23f;

	--ink: #12101a;
	--void: #0c0a14;
	--cream: #fffbf2;
	--chalk: #f7f3ff;

	/* Dark is the default ground. */
	--bg: var(--void);
	--bg-raised: #17142212;
	--fg: var(--chalk);
	--on-hue: var(--ink);

	/* Hue-as-text. On the dark ground the raw hue is already 5.7:1 or better. */
	--lime-text: var(--lime);
	--cyan-text: var(--cyan);
	--violet-text: var(--violet);
	--pink-text: var(--pink);
	--orange-text: var(--orange);
	--yellow-text: var(--yellow);

	/* Derived, not picked. 62% is the floor for the faint tier: below it it
	   drops under 4.5:1 on cream, and every use of it is small text. */
	--fg-muted: color-mix(in srgb, var(--fg) 74%, var(--bg));
	--fg-faint: color-mix(in srgb, var(--fg) 62%, var(--bg));
	--line-soft: color-mix(in srgb, var(--fg) 26%, var(--bg));
	--panel: color-mix(in srgb, var(--fg) 6%, var(--bg));

	/* The hue a component paints itself with. Rotated per card in PHP. */
	--hue: var(--violet);
	--hue-text: var(--violet-text);

	--font-display: "Bricolage Grotesque", ui-rounded, "Segoe UI", "Noto Sans Hebrew", system-ui, sans-serif;
	--font-body: "Space Grotesk", ui-sans-serif, system-ui, "Noto Sans Hebrew", "Arial Hebrew", sans-serif;
	--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

	--step--1: clamp(0.78rem, 0.76rem + 0.1vw, 0.85rem);
	--step-0: clamp(1rem, 0.96rem + 0.2vw, 1.12rem);
	--step-1: clamp(1.2rem, 1.1rem + 0.5vw, 1.5rem);
	--step-2: clamp(1.5rem, 1.28rem + 1.1vw, 2.2rem);
	--step-3: clamp(2rem, 1.55rem + 2.2vw, 3.4rem);
	--step-4: clamp(2.6rem, 1.5rem + 5.5vw, 6.5rem);

	--space-1: 0.4rem;
	--space-2: 0.8rem;
	--space-3: 1.35rem;
	--space-4: 2.2rem;
	--space-5: 3.6rem;
	--space-6: 5.5rem;

	--radius-s: 10px;
	--radius: 18px;
	--radius-l: 30px;
	--rule: 3px;
	--border: var(--rule) solid var(--fg);
	--wrap: 78rem;
	--measure: 64ch;

	/* One spring, used everywhere. Overshoots, settles, feels alive. */
	--spring: cubic-bezier(0.34, 1.56, 0.64, 1);
	--fast: 0.18s;
	--slow: 0.5s;

	/* Pointer position, 0-1 across the viewport. Written by js/lab.js. */
	--mx: 0.5;
	--my: 0.5;
}

@media (prefers-color-scheme: light) {
	:root:not([data-scheme="dark"]) {
		--bg: var(--cream);
		--fg: var(--ink);
		--lime-text: #5c7a23;
		--cyan-text: #1a7b89;
		--violet-text: #8259cf;
		--pink-text: #c13e7f;
		--orange-text: #a95d25;
		--yellow-text: #856e2c;
	}
}

:root[data-scheme="light"] {
	--bg: var(--cream);
	--fg: var(--ink);
	--lime-text: #5c7a23;
	--cyan-text: #1a7b89;
	--violet-text: #8259cf;
	--pink-text: #c13e7f;
	--orange-text: #a95d25;
	--yellow-text: #856e2c;
}

/* Hue assignment. Cards, sections and pills opt into one of six. */
.hue-lime { --hue: var(--lime); --hue-text: var(--lime-text); }
.hue-cyan { --hue: var(--cyan); --hue-text: var(--cyan-text); }
.hue-violet { --hue: var(--violet); --hue-text: var(--violet-text); }
.hue-pink { --hue: var(--pink); --hue-text: var(--pink-text); }
.hue-orange { --hue: var(--orange); --hue-text: var(--orange-text); }
.hue-yellow { --hue: var(--yellow); --hue-text: var(--yellow-text); }

/* OVERCLOCK: the konami-code easter egg. Everything gets louder. */
:root[data-overclock] {
	--spring: cubic-bezier(0.2, 2.2, 0.3, 1);
}

/*
 * The drift goes on #page, not on body. A filter creates a containing block
 * for every position: fixed descendant, so filtering body re-anchored .cursor
 * and .toasts to the document instead of the viewport: the custom cursor
 * lagged behind the pointer and drifted off-screen on a scrolled page, and
 * every toast landed at the top of the document rather than the corner of the
 * screen. #page carries no fixed descendants, because both of those are
 * appended to body, so the same effect applies without the trap.
 */
:root[data-overclock] #page {
	animation: berns-lab-hue-drift 6s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
	:root[data-overclock] #page {
		animation: none;
	}
}

@keyframes berns-lab-hue-drift {
	to {
		filter: hue-rotate(360deg);
	}
}

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

* {
	margin: 0;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
}

img,
svg,
video,
canvas,
iframe {
	display: block;
	max-inline-size: 100%;
	block-size: auto;
}

/* One switch disables the whole show. Everything below that floats, tilts,
   drifts, marquees or springs is gated on it. */
@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}

	.blob,
	.cursor,
	.preloader {
		display: none !important;
	}

	.marquee__track {
		animation: none !important;
		transform: none !important;
	}
}

/*--------------------------------------------------------------
# Base typography
--------------------------------------------------------------*/
body {
	background-color: var(--bg);
	color: var(--fg);
	font-family: var(--font-body);
	font-size: var(--step-0);
	font-weight: 400;
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
}

h1,
h2,
h3,
h4,
h5,
h6 {
	font-family: var(--font-display);
	font-weight: 800;
	font-stretch: 100%;
	line-height: 0.98;
	letter-spacing: -0.03em;
	text-wrap: balance;
}

h1 {
	font-size: var(--step-3);
}

h2 {
	font-size: var(--step-2);
}

h3 {
	font-size: var(--step-1);
}

p,
ul,
ol,
blockquote,
figure,
pre,
table {
	margin-block: 0 var(--space-3);
}

p {
	text-wrap: pretty;
}

a {
	color: var(--hue-text);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.18em;
	text-decoration-skip-ink: auto;
	transition: color var(--fast) var(--spring);
}

a:hover {
	color: var(--pink-text);
}

:focus-visible {
	outline: var(--rule) solid var(--fg);
	outline-offset: 3px;
	box-shadow: 0 0 0 7px var(--hue);
	border-radius: var(--radius-s);
}

code,
kbd,
samp,
pre {
	font-family: var(--font-mono);
	font-size: 0.9em;
}

code {
	background: var(--hue);
	color: var(--on-hue);
	padding-inline: 0.35em;
	border-radius: 6px;
	font-weight: 500;
}

pre {
	border: var(--border);
	border-radius: var(--radius);
	padding: var(--space-3);
	overflow-x: auto;
	line-height: 1.55;
	background: var(--panel);
}

pre code {
	background: none;
	color: inherit;
	padding: 0;
}

blockquote {
	border-inline-start: 8px solid var(--hue);
	border-radius: var(--radius-s);
	padding: var(--space-2) var(--space-3);
	background: var(--panel);
	font-size: var(--step-1);
	font-weight: 500;
}

hr {
	border: 0;
	block-size: var(--rule);
	background: var(--fg);
	border-radius: 99px;
	margin-block: var(--space-4);
}

table {
	inline-size: 100%;
	border-collapse: collapse;
	font-size: var(--step--1);
}

th,
td {
	text-align: start;
	padding: var(--space-2);
	border-block-end: 2px solid var(--line-soft);
}

/* The label voice: small, tracked, loud. */
.eyebrow,
.lab-section__title,
.status-pill,
.tag-row__item,
.filter-row__item,
.project-card__codename,
.project-spec__title,
.sentinel__heading,
.widget-title,
.entry-meta,
.entry-footer {
	font-family: var(--font-body);
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	font-size: var(--step--1);
}

/*--------------------------------------------------------------
# Decor: blobs, stickers, marquee
--------------------------------------------------------------*/

/* Floating gradient blobs behind the hero. Purely decorative, aria-hidden,
   and they drift with the pointer via --mx/--my. */
.blob-field {
	position: absolute;
	inset: 0;
	overflow: hidden;
	pointer-events: none;
	z-index: 0;
	border-radius: var(--radius-l);
}

.blob {
	position: absolute;
	inline-size: 30rem;
	block-size: 30rem;
	border-radius: 50%;
	filter: blur(55px);
	opacity: 0.55;
	will-change: transform;
	transition: transform 1.2s var(--spring);
}

.blob--1 {
	background: var(--violet);
	inset-block-start: -10rem;
	inset-inline-start: 55%;
	transform: translate3d(calc(var(--mx) * 60px), calc(var(--my) * 50px), 0);
	animation: berns-lab-float-a 14s ease-in-out infinite;
}

.blob--2 {
	background: var(--cyan);
	inset-block-start: 12%;
	inset-inline-end: -6rem;
	transform: translate3d(calc(var(--mx) * -70px), calc(var(--my) * 40px), 0);
	animation: berns-lab-float-b 18s ease-in-out infinite;
}

.blob--3 {
	background: var(--pink);
	inset-block-end: -12rem;
	inset-inline-start: 45%;
	inline-size: 24rem;
	block-size: 24rem;
	transform: translate3d(calc(var(--mx) * 45px), calc(var(--my) * -55px), 0);
	animation: berns-lab-float-a 11s ease-in-out infinite reverse;
}

@keyframes berns-lab-float-a {
	0%,
	100% {
		margin-block-start: 0;
	}

	50% {
		margin-block-start: 3rem;
	}
}

@keyframes berns-lab-float-b {
	0%,
	100% {
		margin-inline-start: 0;
	}

	50% {
		margin-inline-start: -3rem;
	}
}

/* The two-column promise only holds while there are two columns. Once the
   text spans the whole hero there is nowhere safe to put a saturated blob
   behind it, so the art steps back and then leaves entirely. This is the
   rule that keeps the measured contrast true at every width, not just wide
   desktop. */
@media (max-width: 68rem) {
	.blob {
		opacity: 0.16;
	}
}

@media (max-width: 46rem) {
	.blob-field {
		display: none;
	}
}

/* Scroll reveal. No JS, no reveal, content is visible by default and the
   observer only opts elements into the animation. */
.js .reveal {
	opacity: 0;
	transform: translateY(22px);
	transition: opacity var(--slow) ease, transform var(--slow) var(--spring);
}

.js .reveal.is-in {
	opacity: 1;
	transform: none;
}

.marquee {
	overflow: hidden;
	border-block: var(--border);
	background: var(--hue);
	color: var(--on-hue);
	padding-block: 0.5rem;
	margin-block: var(--space-5);
	transform: rotate(-1.2deg);
}

.marquee__track {
	display: flex;
	gap: var(--space-4);
	inline-size: max-content;
	animation: berns-lab-marquee 26s linear infinite;
	font-family: var(--font-display);
	font-weight: 800;
	font-size: var(--step-1);
	letter-spacing: -0.01em;
	text-transform: uppercase;
}

.marquee:hover .marquee__track {
	animation-play-state: paused;
}

.marquee__item {
	display: flex;
	align-items: center;
	gap: var(--space-4);
	white-space: nowrap;
}

@keyframes berns-lab-marquee {
	to {
		transform: translateX(-50%);
	}
}

[dir="rtl"] .marquee__track {
	animation-direction: reverse;
}

/*--------------------------------------------------------------
# Layout
--------------------------------------------------------------*/
.site {
	display: flex;
	flex-direction: column;
	min-block-size: 100vh;
	position: relative;
}

.site-main {
	inline-size: min(100% - 2.5rem, var(--wrap));
	margin-inline: auto;
	padding-block: var(--space-5) var(--space-6);
	flex: 1 0 auto;
	position: relative;
	z-index: 1;
}

.site-main--single {
	inline-size: min(100% - 2.5rem, var(--measure));
}

.lab-section {
	margin-block-start: var(--space-5);
}

.lab-section__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	margin-block-end: var(--space-3);
}

.lab-section__title {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	background: var(--hue);
	color: var(--on-hue);
	padding-inline: 0.9rem;
	padding-block: 0.35rem;
	border-radius: 99px;
	border: var(--border);
	transform: rotate(-1.5deg);
}

.lab-section__more {
	font-weight: 700;
	text-decoration: none;
	color: var(--fg);
}

.lab-section__more:hover {
	color: var(--hue-text);
}

.page-header {
	margin-block-end: var(--space-4);
}

.page-title {
	font-size: var(--step-3);
}

.page-subtitle {
	color: var(--fg-muted);
	max-inline-size: var(--measure);
	margin-block-start: var(--space-2);
	font-size: var(--step-1);
}

.eyebrow,
.page-header__eyebrow {
	display: inline-block;
	background: var(--hue);
	color: var(--on-hue);
	padding-inline: 0.8rem;
	padding-block: 0.25rem;
	border: var(--border);
	border-radius: 99px;
	margin-block-end: var(--space-2);
	transform: rotate(-2deg);
}

/* A link inside the pill inherits the pill's ink. Without this it picks up the
   global link colour, which is --hue-text, and a violet link on a violet fill
   is an empty pill. Found by screenshotting the note template. */
.page-header__eyebrow a {
	color: inherit;
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}

.page-header__eyebrow a:hover {
	text-decoration-style: wavy;
}

/*--------------------------------------------------------------
# Header & navigation
--------------------------------------------------------------*/
.site-header {
	position: sticky;
	inset-block-start: 0;
	z-index: 40;
	background: color-mix(in srgb, var(--bg) 82%, transparent);
	backdrop-filter: blur(14px) saturate(150%);
	border-block-end: var(--border);
}

.site-header__inner {
	inline-size: min(100% - 2.5rem, var(--wrap));
	margin-inline: auto;
	display: flex;
	align-items: center;
	gap: var(--space-3);
	padding-block: var(--space-2);
}

.site-branding {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	margin-inline-end: auto;
}

.site-mark {
	color: var(--fg);
	flex: none;
	transition: transform var(--fast) var(--spring);
}

.site-mark:hover {
	transform: rotate(-12deg) scale(1.12);
}

.site-title {
	font-family: var(--font-display);
	font-size: var(--step-1);
	font-weight: 800;
	letter-spacing: -0.03em;
	line-height: 1;
}

.site-title a {
	text-decoration: none;
	color: var(--fg);
}

.site-title a:hover {
	color: var(--hue-text);
}

.site-description {
	font-size: var(--step--1);
	color: var(--fg-faint);
	font-weight: 500;
}

@media (max-width: 62rem) {
	.site-description {
		display: none;
	}
}

.main-navigation ul {
	list-style: none;
	display: flex;
	align-items: center;
	gap: var(--space-1);
	margin: 0;
	padding: 0;
}

.main-navigation a {
	display: block;
	font-weight: 700;
	font-size: var(--step--1);
	text-decoration: none;
	color: var(--fg);
	padding-inline: 0.85rem;
	padding-block: 0.4rem;
	border-radius: 99px;
	border: 2px solid transparent;
	transition: background var(--fast) var(--spring), transform var(--fast) var(--spring), border-color var(--fast) ease;
}

.main-navigation a:hover,
.main-navigation .current-menu-item > a {
	background: var(--hue);
	color: var(--on-hue);
	border-color: var(--fg);
	transform: rotate(-2deg) scale(1.05);
}

.main-navigation li:nth-child(2) a:hover { background: var(--cyan); }
.main-navigation li:nth-child(3) a:hover { background: var(--lime); }
.main-navigation li:nth-child(4) a:hover { background: var(--orange); }

.main-navigation ul ul {
	display: none;
	position: absolute;
	flex-direction: column;
	align-items: stretch;
	background: var(--bg);
	border: var(--border);
	border-radius: var(--radius);
	padding: 0.4rem;
	min-inline-size: 12rem;
	box-shadow: 6px 6px 0 var(--hue);
}

.main-navigation li {
	position: relative;
}

.main-navigation li:hover > ul,
.main-navigation li:focus-within > ul {
	display: flex;
}

.menu-toggle {
	display: none;
}

.theme-toggle {
	background: var(--bg);
	border: var(--border);
	border-radius: 99px;
	inline-size: 2.5rem;
	block-size: 2.5rem;
	display: grid;
	place-items: center;
	cursor: pointer;
	flex: none;
	padding: 0;
	transition: transform var(--fast) var(--spring), background var(--fast) ease;
}

.theme-toggle__glyph {
	inline-size: 1.1rem;
	block-size: 1.1rem;
	border-radius: 50%;
	background: linear-gradient(120deg, var(--yellow) 0 50%, var(--violet) 50% 100%);
	border: 2px solid var(--fg);
}

.theme-toggle:hover {
	transform: rotate(180deg) scale(1.1);
	background: var(--hue);
}

@media (max-width: 48rem) {
	.menu-toggle {
		display: grid;
		place-items: center;
		inline-size: 2.5rem;
		block-size: 2.5rem;
		background: var(--hue);
		border: var(--border);
		border-radius: 99px;
		cursor: pointer;
		order: 3;
		padding: 0;
	}

	.menu-toggle__bars,
	.menu-toggle__bars::before,
	.menu-toggle__bars::after {
		display: block;
		inline-size: 1.05rem;
		block-size: 2.5px;
		background: var(--on-hue);
		border-radius: 99px;
		content: "";
	}

	.menu-toggle__bars {
		position: relative;
	}

	.menu-toggle__bars::before {
		position: absolute;
		inset-block-start: -6px;
	}

	.menu-toggle__bars::after {
		position: absolute;
		inset-block-start: 6px;
	}

	.main-navigation ul {
		display: none;
	}

	/*
	 * The child combinator matters. As a descendant selector this also matched
	 * every nested submenu UL, and at specificity (0,2,1) it beat the
	 * (0,1,2) rule that keeps them hidden, so opening the menu dropped every
	 * submenu on top of its own parent list, absolutely positioned.
	 */
	.main-navigation.toggled > ul {
		display: flex;
		flex-direction: column;
		align-items: stretch;
		position: absolute;
		inset-inline: 1.25rem;
		inset-block-start: calc(100% + 0.5rem);
		background: var(--bg);
		border: var(--border);
		border-radius: var(--radius);
		padding: 0.5rem;
		box-shadow: 8px 8px 0 var(--violet);
	}

	/*
	 * Submenus stack inside the panel on a small screen rather than floating
	 * over it. Static position, so they take part in the column flow.
	 */
	.main-navigation.toggled ul ul {
		position: static;
		inline-size: 100%;
		border: 0;
		box-shadow: none;
		padding-inline-start: 0.75rem;
		min-inline-size: 0;
	}

	.main-navigation.toggled li:hover > ul,
	.main-navigation.toggled li:focus-within > ul {
		display: flex;
	}

	.main-navigation {
		position: static;
	}

	.site-header__inner {
		position: relative;
	}
}

/*--------------------------------------------------------------
# Hero
--------------------------------------------------------------*/
.lab-hero {
	position: relative;
	padding: var(--space-5) var(--space-4) var(--space-6);
	margin-block-end: var(--space-4);
	border: var(--border);
	border-radius: var(--radius-l);
	overflow: hidden;
	isolation: isolate;
}

/* Content sits above the decor. The blob field is positioned with a z-index,
   so without this the static children paint underneath it. */
.lab-hero > *,
.project-single__header > * {
	position: relative;
	z-index: 1;
}

/* A scrim between the blobs and the text.
   It has to be ::after, not ::before: the blob field is a real child with
   z-index 0, so a ::before at the same level paints UNDERNEATH it and does
   nothing at all. ::after paints after the field and below the content, which
   sits at z-index 1. Measured worst-case backdrop contrast, not eyeballed. */
.lab-hero::after,
.project-single__header::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	/* The hero is two columns: type on the reading side, art on the other.
	   The scrim holds the ground solid across the reading side and releases
	   entirely past it, so the blobs stay fully saturated exactly where no
	   text can reach. The type caps below are what make that promise keepable, widen them and this stops being true. Measured, not eyeballed. */
	background: linear-gradient(
		to right,
		var(--bg) 0%,
		var(--bg) 55%,
		color-mix(in srgb, var(--bg) 55%, transparent) 68%,
		transparent 78%
	);
}

[dir="rtl"] .lab-hero::after,
[dir="rtl"] .project-single__header::after {
	background: linear-gradient(
		to left,
		var(--bg) 0%,
		var(--bg) 55%,
		color-mix(in srgb, var(--bg) 55%, transparent) 68%,
		transparent 78%
	);
}

/* The blob field is a direct child too, so the rule above would otherwise
   make it position:relative and collapse it to nothing inside overflow:hidden. */
.lab-hero .blob-field,
.project-single__header .blob-field {
	position: absolute;
	inset: 0;
	z-index: 0;
}

.lab-hero__kicker {
	display: inline-block;
	background: var(--lime);
	color: var(--on-hue);
	font-weight: 700;
	font-size: var(--step--1);
	letter-spacing: 0.1em;
	text-transform: uppercase;
	padding-inline: 0.9rem;
	padding-block: 0.3rem;
	border: var(--border);
	border-radius: 99px;
	margin-block-end: var(--space-3);
	transform: rotate(-2deg);
	box-shadow: 4px 4px 0 var(--fg);
}

.lab-hero__headline {
	font-family: var(--font-display);
	font-size: var(--step-4);
	font-weight: 800;
	font-stretch: 88%;
	letter-spacing: -0.045em;
	line-height: 0.9;
	max-inline-size: 13ch;
	margin-block-end: var(--space-3);
}

/* Each word can be wrapped by JS to animate independently. */
.lab-hero__headline .word {
	display: inline-block;
	transition: font-stretch var(--slow) var(--spring), color var(--slow) var(--spring), transform var(--slow) var(--spring);
}

.lab-hero__headline .word:hover {
	font-stretch: 75%;
	color: var(--hue-text);
	transform: translateY(-6px) rotate(-3deg);
}

.lab-hero__standfirst {
	color: var(--fg-muted);
	max-inline-size: 44ch;
	font-size: var(--step-1);
	line-height: 1.5;
}

.lab-hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin-block-start: var(--space-4);
}

/*--------------------------------------------------------------
# Sentinel
--------------------------------------------------------------*/
.sentinel {
	margin-block-start: var(--space-4);
	border: var(--border);
	border-radius: var(--radius);
	background: var(--panel);
	overflow: hidden;
}

.sentinel__heading {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	background: var(--cyan);
	color: var(--on-hue);
	padding-inline: var(--space-3);
	padding-block: 0.5rem;
	border-block-end: var(--border);
}

.sentinel__pulse {
	inline-size: 0.6rem;
	block-size: 0.6rem;
	border-radius: 50%;
	background: var(--on-hue);
	animation: berns-lab-pulse 1.8s var(--spring) infinite;
}

@keyframes berns-lab-pulse {
	0%,
	100% {
		transform: scale(1);
		opacity: 1;
	}

	50% {
		transform: scale(1.55);
		opacity: 0.45;
	}
}

.sentinel__list {
	list-style: none;
	margin: 0;
	padding: var(--space-2) var(--space-3);
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(21rem, 1fr));
	gap: 0 var(--space-4);
}

.sentinel__item {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	font-size: var(--step--1);
	font-weight: 500;
	padding-block: 0.45rem;
	border-block-end: 2px solid var(--line-soft);
}

/* State is shape + word, never hue alone, the markers differ in fill so a
   greyscale or colour-blind reading still separates them. */
.sentinel__dot {
	inline-size: 0.75rem;
	block-size: 0.75rem;
	border-radius: 50%;
	flex: none;
	border: 2.5px solid var(--fg);
	background: transparent;
}

.sentinel__dot--up {
	background: var(--lime);
}

.sentinel__dot--degraded {
	background: linear-gradient(135deg, var(--orange) 0 50%, transparent 50% 100%);
}

.sentinel__dot--down {
	background: var(--pink);
	animation: berns-lab-pulse 1s var(--spring) infinite;
}

.sentinel__name {
	text-decoration: none;
	color: var(--fg);
	font-weight: 600;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.sentinel__name:hover {
	color: var(--cyan-text);
}

.sentinel__state {
	margin-inline-start: auto;
	font-weight: 700;
	font-size: 0.7rem;
	letter-spacing: 0.08em;
	padding-inline: 0.5rem;
	padding-block: 0.05rem;
	border-radius: 99px;
	border: 2px solid var(--line-soft);
}

.sentinel__meta {
	color: var(--fg-faint);
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
	min-inline-size: 4em;
	text-align: end;
}

.sentinel__foot {
	margin: 0;
	padding: var(--space-2) var(--space-3);
	border-block-start: 2px solid var(--line-soft);
	font-size: var(--step--1);
	color: var(--fg-faint);
}

/*--------------------------------------------------------------
# Project grid & cards
--------------------------------------------------------------*/
.project-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr));
	gap: var(--space-4);
	perspective: 1000px;
}

.project-card {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	background: var(--bg);
	border: var(--border);
	border-radius: var(--radius);
	padding: var(--space-3);
	position: relative;
	box-shadow: 7px 7px 0 var(--hue);
	transform-style: preserve-3d;
	transition: box-shadow var(--fast) var(--spring), transform var(--slow) var(--spring);
	will-change: transform;
}

/* The tilt itself is written as a custom property by js/lab.js so the CSS
   keeps ownership of everything else in the transform. */
.project-card {
	transform: rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
}

.project-card:hover,
.project-card:focus-within {
	box-shadow: 12px 12px 0 var(--hue);
}

.project-card__media {
	display: block;
	margin: calc(var(--space-3) * -1) calc(var(--space-3) * -1) 0;
	border-block-end: var(--border);
	border-start-start-radius: 15px;
	border-start-end-radius: 15px;
	overflow: hidden;
}

.project-card__media img {
	inline-size: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	transition: transform var(--slow) var(--spring);
}

.project-card:hover .project-card__media img {
	transform: scale(1.06);
}

.project-card__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-2);
}

.project-card__codename {
	color: var(--fg-faint);
}

.project-card__version {
	font-family: var(--font-mono);
	font-size: var(--step--1);
	color: var(--fg-faint);
	font-variant-numeric: tabular-nums;
}

.project-card__title {
	font-family: var(--font-display);
	font-size: var(--step-1);
	font-weight: 800;
	line-height: 1.05;
	letter-spacing: -0.03em;
}

.project-card__title a {
	text-decoration: none;
	color: var(--fg);
}

.project-card__title a:hover {
	color: var(--hue-text);
}

.project-card__title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.project-card__tagline {
	color: var(--fg-muted);
	font-size: var(--step--1);
	margin: 0;
	flex: 1 1 auto;
}

.project-card__footer {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-2);
	padding-block-start: var(--space-2);
	border-block-start: 2px solid var(--line-soft);
}

.status-pill {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	font-size: 0.7rem;
	background: var(--hue);
	color: var(--on-hue);
	padding-inline: 0.6rem;
	padding-block: 0.15rem;
	border: 2.5px solid var(--fg);
	border-radius: 99px;
}

.status-pill__dot {
	inline-size: 0.42rem;
	block-size: 0.42rem;
	border-radius: 50%;
	background: currentColor;
}

.status-pill--live { background: var(--lime); }
.status-pill--beta { background: var(--cyan); }
.status-pill--building { background: var(--yellow); }
.status-pill--design { background: var(--pink); }
.status-pill--research { background: var(--violet); }

.status-pill--paused,
.status-pill--archived {
	background: transparent;
	color: var(--fg-faint);
	border-color: var(--fg-faint);
}

.progress {
	block-size: 12px;
	border: 2.5px solid var(--fg);
	border-radius: 99px;
	padding: 1.5px;
	overflow: hidden;
}

.progress__bar {
	display: block;
	block-size: 100%;
	background: var(--hue);
	border-radius: 99px;
	transition: inline-size 1.2s var(--spring);
}

.tag-row {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem;
}

.tag-row__item {
	font-size: 0.7rem;
	color: var(--fg-muted);
	border: 2px solid var(--line-soft);
	border-radius: 99px;
	padding-inline: 0.55rem;
	padding-block: 0.08rem;
	transition: transform var(--fast) var(--spring), background var(--fast) ease, color var(--fast) ease;
}

.tag-row__item:hover {
	background: var(--hue);
	color: var(--on-hue);
	border-color: var(--fg);
	transform: rotate(-3deg) scale(1.08);
}

.tag-row--links .tag-row__item a {
	text-decoration: none;
	color: inherit;
	position: relative;
	z-index: 1;
}

.filter-row {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-block-end: var(--space-4);
}

.filter-row__item {
	text-decoration: none;
	color: var(--fg);
	border: var(--border);
	border-radius: 99px;
	padding-inline: 0.9rem;
	padding-block: 0.3rem;
	transition: transform var(--fast) var(--spring), background var(--fast) ease, box-shadow var(--fast) ease;
}

.filter-row__item:nth-child(6n + 1) { --hue: var(--violet); }
.filter-row__item:nth-child(6n + 2) { --hue: var(--cyan); }
.filter-row__item:nth-child(6n + 3) { --hue: var(--lime); }
.filter-row__item:nth-child(6n + 4) { --hue: var(--pink); }
.filter-row__item:nth-child(6n + 5) { --hue: var(--orange); }
.filter-row__item:nth-child(6n + 6) { --hue: var(--yellow); }

.filter-row__item.is-current,
.filter-row__item:hover {
	background: var(--hue);
	color: var(--on-hue);
	transform: translateY(-3px) rotate(-1.5deg);
	box-shadow: 4px 4px 0 var(--fg);
}

.filter-row__count {
	opacity: 0.6;
	font-variant-numeric: tabular-nums;
}

/*--------------------------------------------------------------
# Project single
--------------------------------------------------------------*/
.project-single__header {
	padding: var(--space-4);
	border: var(--border);
	border-radius: var(--radius-l);
	background: var(--panel);
	position: relative;
	overflow: hidden;
}

.project-single__eyebrow {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	margin-block-end: var(--space-3);
}

.project-single__title {
	font-family: var(--font-display);
	font-size: var(--step-4);
	font-weight: 800;
	font-stretch: 88%;
	line-height: 0.9;
	letter-spacing: -0.045em;
	max-inline-size: 12ch;
}

.project-single__tagline {
	color: var(--fg-muted);
	font-size: var(--step-1);
	max-inline-size: 44ch;
	margin-block-start: var(--space-3);
}

.project-single__links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin-block-start: var(--space-4);
}

.project-single__media {
	margin-block: var(--space-4);
	border: var(--border);
	border-radius: var(--radius);
	overflow: hidden;
	box-shadow: 10px 10px 0 var(--hue);
}

.project-single__body {
	display: grid;
	gap: var(--space-5);
	grid-template-columns: minmax(0, 1fr);
	padding-block-start: var(--space-4);
}

@media (min-width: 62rem) {
	.project-single__body {
		grid-template-columns: minmax(0, 1fr) 19rem;
	}

	.project-spec {
		position: sticky;
		inset-block-start: 6rem;
		align-self: start;
	}
}

.entry-content {
	max-inline-size: var(--measure);
	font-size: var(--step-0);
}

.entry-content > * + * {
	margin-block-start: var(--space-3);
}

.entry-content h2 {
	margin-block-start: var(--space-5);
	font-size: var(--step-2);
}

.entry-content h3 {
	margin-block-start: var(--space-4);
}

.entry-content ul {
	list-style: none;
	padding-inline-start: 0;
}

.entry-content ul li {
	padding-inline-start: 1.6rem;
	position: relative;
}

.entry-content ul li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: 0.55em;
	inline-size: 0.6rem;
	block-size: 0.6rem;
	border-radius: 50%;
	background: var(--hue);
	border: 2px solid var(--fg);
}

.entry-content ol {
	padding-inline-start: 1.4rem;
}

.entry-content li + li {
	margin-block-start: 0.45rem;
}

.project-spec {
	border: var(--border);
	border-radius: var(--radius);
	padding: var(--space-3);
	background: var(--bg);
	box-shadow: 7px 7px 0 var(--hue);
}

.project-spec__title {
	display: inline-block;
	background: var(--hue);
	color: var(--on-hue);
	padding-inline: 0.7rem;
	padding-block: 0.2rem;
	border: 2.5px solid var(--fg);
	border-radius: 99px;
	margin-block-end: var(--space-2);
	transform: rotate(-1.5deg);
}

.project-spec__title ~ .project-spec__title {
	margin-block-start: var(--space-4);
}

.project-spec__list {
	margin: 0;
}

.project-spec__row {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-2);
	padding-block: 0.45rem;
	border-block-end: 2px solid var(--line-soft);
	font-size: var(--step--1);
}

.project-spec__row dt {
	color: var(--fg-faint);
	font-weight: 500;
}

.project-spec__row dd {
	margin: 0;
	font-weight: 700;
	text-align: end;
	font-variant-numeric: tabular-nums;
}

/*--------------------------------------------------------------
# Notes & archives
--------------------------------------------------------------*/
.note-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--space-2);
}

.note-list__item {
	display: flex;
	align-items: baseline;
	gap: var(--space-3);
	padding: var(--space-2) var(--space-3);
	border: var(--border);
	border-radius: var(--radius);
	transition: transform var(--fast) var(--spring), box-shadow var(--fast) var(--spring);
}

.note-list__item:nth-child(4n + 1) { --hue: var(--cyan); }
.note-list__item:nth-child(4n + 2) { --hue: var(--pink); }
.note-list__item:nth-child(4n + 3) { --hue: var(--lime); }
.note-list__item:nth-child(4n + 4) { --hue: var(--orange); }

.note-list__item:hover {
	transform: translate(-3px, -3px);
	box-shadow: 7px 7px 0 var(--hue);
}

.note-list__link {
	text-decoration: none;
	color: var(--fg);
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	flex: 1 1 auto;
}

.note-list__title {
	font-family: var(--font-display);
	font-weight: 800;
	font-size: var(--step-1);
	letter-spacing: -0.02em;
}

.note-list__item:hover .note-list__title {
	color: var(--hue-text);
}

.note-list__excerpt {
	color: var(--fg-muted);
	font-size: var(--step--1);
}

.note-list__date {
	font-family: var(--font-mono);
	font-size: var(--step--1);
	color: var(--fg-faint);
	flex: none;
}

.entry-header {
	margin-block-end: var(--space-3);
}

.entry-title {
	font-size: var(--step-3);
}

.entry-title a {
	text-decoration: none;
	color: var(--fg);
}

.entry-meta,
.entry-footer {
	color: var(--fg-faint);
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	margin-block-start: var(--space-2);
}

.entry-footer {
	padding-block-start: var(--space-3);
	border-block-start: 2px solid var(--line-soft);
	margin-block-start: var(--space-4);
}

.post,
.page {
	margin-block-end: var(--space-5);
}

.navigation.pagination,
.post-navigation {
	margin-block-start: var(--space-5);
	padding-block-start: var(--space-3);
	border-block-start: 2px solid var(--line-soft);
	font-weight: 700;
}

.nav-links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	justify-content: space-between;
}

.page-numbers {
	text-decoration: none;
	color: var(--fg);
	border: var(--border);
	border-radius: 99px;
	padding-inline: 0.8rem;
	padding-block: 0.25rem;
}

.page-numbers.current,
.page-numbers:hover {
	background: var(--hue);
	color: var(--on-hue);
}

.widget {
	margin-block-end: var(--space-4);
}

.widget-title {
	color: var(--fg-faint);
	margin-block-end: var(--space-2);
}

.widget ul {
	list-style: none;
	padding: 0;
}

/*--------------------------------------------------------------
# Forms & buttons
--------------------------------------------------------------*/
input[type="text"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"],
input[type="number"],
input[type="tel"],
input[type="date"],
textarea,
select {
	inline-size: 100%;
	max-inline-size: 100%;
	font-family: var(--font-body);
	font-size: var(--step-0);
	color: var(--fg);
	background: var(--bg);
	border: var(--border);
	border-radius: var(--radius-s);
	padding: 0.6rem 0.85rem;
	transition: box-shadow var(--fast) var(--spring);
}

input:focus,
textarea:focus,
select:focus {
	box-shadow: 4px 4px 0 var(--hue);
}

.button,
button,
input[type="submit"],
.wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-family: var(--font-body);
	font-size: var(--step-0);
	font-weight: 700;
	letter-spacing: -0.01em;
	text-decoration: none;
	cursor: pointer;
	padding-inline: 1.4rem;
	padding-block: 0.7rem;
	border: var(--border);
	border-radius: 99px;
	background: var(--bg);
	color: var(--fg);
	box-shadow: 5px 5px 0 var(--fg);
	transition: transform var(--fast) var(--spring), box-shadow var(--fast) var(--spring), background var(--fast) ease;
}

.button--primary,
input[type="submit"],
.wp-block-button__link {
	background: var(--hue);
	color: var(--on-hue);
}

.button:hover,
button:hover,
input[type="submit"]:hover,
.wp-block-button__link:hover {
	transform: translate(-3px, -3px);
	box-shadow: 8px 8px 0 var(--fg);
	color: var(--on-hue);
	background: var(--hue);
}

/* Squish on press, the whole point of a button that feels like a button. */
.button:active,
button:active,
input[type="submit"]:active {
	transform: translate(2px, 2px) scale(0.97);
	box-shadow: 2px 2px 0 var(--fg);
}

.theme-toggle,
.menu-toggle {
	box-shadow: none;
}

.theme-toggle:hover,
.menu-toggle:hover {
	box-shadow: none;
}

.theme-toggle:active,
.menu-toggle:active {
	transform: scale(0.92);
	box-shadow: none;
}

.search-form {
	display: flex;
	gap: var(--space-2);
	align-items: end;
}

/*--------------------------------------------------------------
# Comments
--------------------------------------------------------------*/
.comments-area {
	margin-block-start: var(--space-5);
	padding-block-start: var(--space-4);
	border-block-start: var(--border);
	max-inline-size: var(--measure);
}

.comment-list {
	list-style: none;
	padding: 0;
}

.comment-list .children {
	list-style: none;
	padding-inline-start: var(--space-3);
	border-inline-start: var(--border);
}

.comment-body {
	padding: var(--space-3);
	border: 2px solid var(--line-soft);
	border-radius: var(--radius);
	margin-block-end: var(--space-2);
}

.comment-meta {
	font-weight: 700;
	font-size: var(--step--1);
	color: var(--fg-faint);
	margin-block-end: var(--space-2);
}

.comment-form label {
	display: block;
	font-weight: 700;
	font-size: var(--step--1);
	color: var(--fg-muted);
	margin-block-end: 0.3rem;
}

.comment-form p {
	margin-block-end: var(--space-2);
}

/*--------------------------------------------------------------
# Blocks & alignments
--------------------------------------------------------------*/
.alignleft {
	float: inline-start;
	margin-inline-end: var(--space-3);
	margin-block-end: var(--space-2);
}

.alignright {
	float: inline-end;
	margin-inline-start: var(--space-3);
	margin-block-end: var(--space-2);
}

.aligncenter {
	margin-inline: auto;
	display: block;
}

.alignwide {
	inline-size: min(100vw - 2.5rem, var(--wrap));
	max-inline-size: none;
	margin-inline: calc(50% - min(100vw - 2.5rem, var(--wrap)) / 2);
}

.alignfull {
	inline-size: 100vw;
	max-inline-size: none;
	margin-inline: calc(50% - 50vw);
}

.wp-caption-text,
figcaption {
	font-size: var(--step--1);
	color: var(--fg-faint);
	margin-block-start: 0.5rem;
	font-weight: 500;
}

.wp-block-image img {
	border: var(--border);
	border-radius: var(--radius);
}

/*--------------------------------------------------------------
# Footer
--------------------------------------------------------------*/
.site-footer {
	border-block-start: var(--border);
	margin-block-start: auto;
	position: relative;
	z-index: 1;
	background: var(--bg);
}

.site-footer__inner {
	inline-size: min(100% - 2.5rem, var(--wrap));
	margin-inline: auto;
	padding-block: var(--space-4);
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-3);
	justify-content: space-between;
}

.site-footer__brand {
	display: flex;
	align-items: center;
	gap: 0.6rem;
}

.site-footer__title {
	font-family: var(--font-display);
	font-weight: 800;
	font-size: var(--step-1);
	letter-spacing: -0.03em;
	margin: 0;
}

.site-footer__note {
	color: var(--fg-faint);
	font-size: var(--step--1);
	margin: 0;
}

.site-footer__menu {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin: 0;
	padding: 0;
	font-weight: 700;
	font-size: var(--step--1);
}

.site-footer__menu a {
	text-decoration: none;
	color: var(--fg-muted);
}

.site-info {
	font-size: var(--step--1);
	color: var(--fg-faint);
	inline-size: 100%;
	padding-block-start: var(--space-3);
	border-block-start: 2px solid var(--line-soft);
	display: flex;
	align-items: center;
	gap: 0.6rem;
	flex-wrap: wrap;
}

/*--------------------------------------------------------------
# Preloader, cursor, toasts, achievements
--------------------------------------------------------------*/
.preloader {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: grid;
	place-items: center;
	background: var(--bg);
	transition: opacity 0.45s ease, visibility 0.45s ease;
}

.preloader.is-done {
	opacity: 0;
	visibility: hidden;
}

.preloader__inner {
	display: grid;
	justify-items: center;
	gap: var(--space-3);
}

.preloader__bolt {
	inline-size: 4.5rem;
	block-size: 4.5rem;
	color: var(--yellow);
	animation: berns-lab-charge 1.1s var(--spring) infinite;
}

@keyframes berns-lab-charge {
	0%,
	100% {
		transform: scale(1) rotate(-6deg);
	}

	50% {
		transform: scale(1.25) rotate(6deg);
	}
}

.preloader__bar {
	inline-size: 12rem;
	block-size: 10px;
	border: 2.5px solid var(--fg);
	border-radius: 99px;
	overflow: hidden;
	padding: 1.5px;
}

.preloader__fill {
	display: block;
	block-size: 100%;
	inline-size: 0;
	border-radius: 99px;
	background: linear-gradient(90deg, var(--violet), var(--cyan), var(--lime));
	animation: berns-lab-load 1.1s ease-out forwards;
}

@keyframes berns-lab-load {
	to {
		inline-size: 100%;
	}
}

.preloader__label {
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	font-size: var(--step--1);
	color: var(--fg-faint);
}

/* Custom cursor. Pointer-events none, coarse pointers excluded in JS. */
.cursor {
	position: fixed;
	inset-block-start: 0;
	inset-inline-start: 0;
	inline-size: 22px;
	block-size: 22px;
	border-radius: 50%;
	background: var(--lime);
	mix-blend-mode: difference;
	pointer-events: none;
	z-index: 9998;
	translate: -50% -50%;
	transition: width 0.2s var(--spring), height 0.2s var(--spring), background 0.2s ease;
	will-change: transform;
}

.cursor.is-hot {
	inline-size: 48px;
	block-size: 48px;
	background: var(--cyan);
}

.toasts {
	position: fixed;
	inset-block-end: 1.25rem;
	inset-inline-end: 1.25rem;
	z-index: 9997;
	display: grid;
	gap: 0.6rem;
	justify-items: end;
	pointer-events: none;
}

.toast {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	background: var(--bg);
	color: var(--fg);
	border: var(--border);
	border-radius: 99px;
	padding: 0.6rem 1.1rem;
	box-shadow: 6px 6px 0 var(--hue);
	font-weight: 700;
	animation: berns-lab-toast-in 0.5s var(--spring);
	max-inline-size: min(22rem, 80vw);
}

.toast__icon {
	inline-size: 1.6rem;
	block-size: 1.6rem;
	display: grid;
	place-items: center;
	border-radius: 50%;
	background: var(--hue);
	color: var(--on-hue);
	flex: none;
}

@keyframes berns-lab-toast-in {
	from {
		opacity: 0;
		transform: translateY(20px) scale(0.9);
	}
}

.achievements {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	font-size: var(--step--1);
	font-weight: 700;
	color: var(--fg-faint);
}

.achievements__slots {
	display: flex;
	gap: 0.3rem;
}

.achievements__slot {
	inline-size: 1.1rem;
	block-size: 1.1rem;
	border-radius: 50%;
	border: 2.5px solid var(--line-soft);
	transition: background var(--fast) var(--spring), border-color var(--fast) ease, transform var(--fast) var(--spring);
}

.achievements__slot.is-won {
	background: var(--hue);
	border-color: var(--fg);
	transform: scale(1.15);
}

.achievements__slot:nth-child(1) { --hue: var(--violet); }
.achievements__slot:nth-child(2) { --hue: var(--cyan); }
.achievements__slot:nth-child(3) { --hue: var(--pink); }

/*--------------------------------------------------------------
# Accessibility & utilities
--------------------------------------------------------------*/
.screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute !important;
	width: 1px;
	word-wrap: normal !important;
}

.screen-reader-text:focus {
	background-color: var(--lime);
	color: var(--on-hue);
	clip-path: none;
	display: block;
	font-weight: 700;
	height: auto;
	inset-inline-start: 1rem;
	inset-block-start: 1rem;
	line-height: normal;
	padding: 0.85rem 1.3rem;
	text-decoration: none;
	width: auto;
	z-index: 100000;
	border: var(--border);
	border-radius: 99px;
}

.skip-link:focus {
	outline-offset: 0;
	box-shadow: none;
}

.sticky {
	position: relative;
}

.bypostauthor {
	display: block;
}

.no-results {
	max-inline-size: var(--measure);
}

/* RTL: the sheet is authored in logical properties, so only the genuinely
   directional pieces, offset shadows, rotations, the marquee, flip here. */
[dir="rtl"] .project-card,
[dir="rtl"] .project-spec,
[dir="rtl"] .project-single__media {
	box-shadow: -7px 7px 0 var(--hue);
}

[dir="rtl"] .project-card:hover,
[dir="rtl"] .project-card:focus-within {
	box-shadow: -12px 12px 0 var(--hue);
}

[dir="rtl"] .button,
[dir="rtl"] button,
[dir="rtl"] input[type="submit"],
[dir="rtl"] .lab-hero__kicker {
	box-shadow: -5px 5px 0 var(--fg);
}

[dir="rtl"] .button:hover,
[dir="rtl"] button:hover,
[dir="rtl"] input[type="submit"]:hover {
	transform: translate(3px, -3px);
	box-shadow: -8px 8px 0 var(--fg);
}

[dir="rtl"] .button:active,
[dir="rtl"] button:active {
	transform: translate(-2px, 2px) scale(0.97);
	box-shadow: -2px 2px 0 var(--fg);
}

[dir="rtl"] .note-list__item:hover {
	transform: translate(3px, -3px);
	box-shadow: -7px 7px 0 var(--hue);
}

[dir="rtl"] .filter-row__item.is-current,
[dir="rtl"] .filter-row__item:hover {
	box-shadow: -4px 4px 0 var(--fg);
}

/*
 * Six offset shadows had no mirror here, so a Hebrew page showed light coming
 * from the top-left on a submenu and a button while every neighbouring card
 * shaded from the top-right. Mixed lighting on one screen reads as a rendering
 * fault rather than a style. Found by deriving the set of offset shadows from
 * the stylesheet and subtracting the ones with a counterpart, which is now a
 * gate in tools/check_css_js.py so a seventh cannot be added unmirrored.
 */
[dir="rtl"] .main-navigation ul ul {
	box-shadow: -6px 6px 0 var(--hue);
}

[dir="rtl"] input:focus,
[dir="rtl"] textarea:focus,
[dir="rtl"] select:focus {
	box-shadow: -4px 4px 0 var(--hue);
}

[dir="rtl"] .wp-block-button__link {
	box-shadow: -5px 5px 0 var(--fg);
}

[dir="rtl"] .wp-block-button__link:hover {
	box-shadow: -8px 8px 0 var(--fg);
	transform: translate(3px, -3px);
}

[dir="rtl"] button:active,
[dir="rtl"] input[type="submit"]:active {
	box-shadow: -2px 2px 0 var(--fg);
	transform: translate(-2px, 2px) scale(0.97);
}

@media (max-width: 48rem) {
	[dir="rtl"] .main-navigation.toggled > ul {
		box-shadow: -8px 8px 0 var(--violet);
	}
}

[dir="rtl"] .toast {
	box-shadow: -6px 6px 0 var(--hue);
}

[dir="rtl"] .lab-section__title,
[dir="rtl"] .eyebrow,
[dir="rtl"] .page-header__eyebrow,
[dir="rtl"] .lab-hero__kicker,
[dir="rtl"] .project-spec__title,
[dir="rtl"] .marquee {
	transform: rotate(1.5deg);
}

[dir="rtl"] .theme-toggle,
[dir="rtl"] .menu-toggle {
	box-shadow: none;
}

/*--------------------------------------------------------------
# Lab notes
--------------------------------------------------------------*/
/* A note is prose. It gets one measure column, no artwork and no spec panel,
   because the thing being read is the sentence rather than the state. */
.lab-note .entry-title {
	font-size: var(--step-3);
	max-inline-size: 18ch;
}

.lab-note .entry-meta {
	align-items: baseline;
	color: var(--fg-faint);
	display: flex;
	flex-wrap: wrap;
	font-family: var(--font-mono);
	font-size: var(--step--1);
	gap: var(--space-2);
	margin-block-start: var(--space-2);
}

.lab-note .entry-meta__updated::before {
	content: "";
	display: inline-block;
	inline-size: 0.35rem;
	block-size: 0.35rem;
	border-radius: 50%;
	background: var(--hue);
	margin-inline-end: 0.45rem;
	vertical-align: middle;
}

.lab-note .entry-content {
	margin-block-start: var(--space-4);
}

.lab-note .entry-footer {
	border-block-start: 2px solid var(--line-soft);
	margin-block-start: var(--space-5);
	padding-block-start: var(--space-3);
}

/*--------------------------------------------------------------
# Empty states
--------------------------------------------------------------*/
/* An empty board is a legitimate state, not an error, so it is styled like a
   panel on the site rather than like a 404. */
.empty-lab {
	border: var(--border);
	border-radius: var(--radius-l);
	box-shadow: 7px 7px 0 var(--hue);
	margin-block-start: var(--space-4);
	padding: var(--space-5) var(--space-4);
	text-align: center;
}

.empty-lab__mark {
	color: var(--hue-text);
	margin: 0 0 var(--space-2);
}

.empty-lab__mark .bolt {
	display: inline-block;
	inline-size: 1.4rem;
	block-size: 3.5rem;
}

.empty-lab__title {
	font-size: var(--step-2);
	margin-block-end: var(--space-2);
}

.empty-lab__body {
	color: var(--fg-muted);
	margin-inline: auto;
	max-inline-size: 46ch;
}

.empty-lab__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	justify-content: center;
	margin-block-start: var(--space-4);
}

[dir="rtl"] .empty-lab {
	box-shadow: -7px 7px 0 var(--hue);
}
