/* Brook landing page: "Clipping, refined" with the Ink accent (DESIGN.md, #41). Paper
 * clippings on a kraft board, and the thing to press is a strip of label tape: ink with
 * paper type by day, light ink with night type at night. Light and dark follow the
 * visitor's system setting (prefers-color-scheme), designed as a pair, with the kit's own
 * values (public/kit/kit.css, --bk-*).
 * Fonts are self-hosted, latin subset (scripts/copy-fonts.sh):
 * Instrument Serif 400 21 KB, Schibsted Grotesk variable 47 KB, 68 KB total.
 *
 * The persona pages (#27): the app demo in a phone first, then the headline,
 * one line and the form on one clipping that overlaps the phone, then how
 * saves get in, the proof, the founding offer, the questions and the footer. */

@font-face {
	font-family: "Instrument Serif";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url(/fonts/instrument-serif-latin-400-normal.woff2) format("woff2");
	unicode-range:
		U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Schibsted Grotesk Variable";
	font-style: normal;
	font-weight: 400 900;
	font-display: swap;
	src: url(/fonts/schibsted-grotesk-latin-wght-normal.woff2)
		format("woff2-variations");
	unicode-range:
		U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Tokens: the kit's values (public/kit/kit.css), light here and night below; DESIGN.md
 * holds the contrast table for both. */
:root {
	--kraft: oklch(0.62 0.07 65);
	--kraft-light: oklch(0.7 0.065 68);
	--kraft-deep: oklch(0.52 0.07 62);
	/* Over the fibre: none by day; at night the fibre shows through at 10 percent. */
	--kraft-veil: oklch(0.62 0.07 65 / 0);
	--paper: oklch(0.99 0.004 95);
	--paper-shade: oklch(0.955 0.006 90);
	--ink: oklch(0.22 0.014 350);
	--ink-soft: oklch(0.46 0.02 350);
	/* The action: the label strip. */
	--action: oklch(0.22 0.014 350);
	--action-press: oklch(0.12 0.01 350);
	--action-label: oklch(0.99 0.004 95);
	/* Matched words and selected text sit on the kraft tint, never a hue of their own. */
	--tint: oklch(0.93 0.035 70);
	--error: oklch(0.47 0.17 25);
	--tape-kraft: oklch(0.8 0.05 75 / 0.7);
	/* The board's deep edge under the footer, and the type on it (5.45:1 by day). */
	--footer-ground: var(--kraft-deep);
	--footer-ink: var(--paper);
	/* The phone's own colors, as the kit draws them (public/kit/kit.css). */
	--device: oklch(0.2 0.012 350);
	--device-edge: oklch(0.36 0.012 350);
	--device-inner: oklch(0.14 0.01 350);
	/* A rim outside the bezel: none by day; at night it keeps the phone from melting into
	 * the night board. */
	--device-rim: oklch(0.2 0.012 350 / 0);

	--font-display: "Instrument Serif", ui-serif, Georgia, serif;
	--font-text:
		"Schibsted Grotesk Variable", "Schibsted Grotesk", ui-sans-serif, sans-serif;
	--text-sm: 0.875rem;
	--text-base: 1.0625rem;
	--text-lg: 1.25rem;
	--display-sm: clamp(2rem, 1.4rem + 2.6vw, 2.75rem);
	--display-md: clamp(2.75rem, 1.6rem + 5vw, 4.25rem);
	--leading-display: 1.02;
	--leading-text: 1.5;
	--tracking-display: -0.015em;
	--weight-text: 400;
	--weight-strong: 600;

	--space-1: 0.25rem;
	--space-2: 0.5rem;
	--space-3: 0.75rem;
	--space-4: 1rem;
	--space-6: 1.5rem;
	--space-8: 2rem;
	--space-12: 3rem;
	--space-16: 4rem;
	--space-24: 6rem;
	--gutter: 1rem;

	--radius-paper: 2px;
	--radius-field: 2px;
	--tape-height: 3rem;

	--shadow-color: 0.32 0.05 55;
	--shadow-rest:
		0.5px 1px 1px oklch(var(--shadow-color) / 0.1), 1px 2px 2px oklch(
			var(--shadow-color) /
			0.1
		),
		2px 4px 4px oklch(var(--shadow-color) / 0.09), 4px 8px 8px oklch(
			var(--shadow-color) /
			0.08
		);
	--shadow-lifted:
		1px 2px 2px oklch(var(--shadow-color) / 0.07), 2px 4px 4px oklch(
			var(--shadow-color) /
			0.07
		),
		4px 8px 8px oklch(var(--shadow-color) / 0.07), 8px 16px 16px oklch(
			var(--shadow-color) /
			0.06
		),
		16px 32px 32px oklch(var(--shadow-color) / 0.05);
	--shadow-tape: 0.5px 1px 1.5px oklch(var(--shadow-color) / 0.18);
	/* The same light as filters, for torn pieces whose mask would clip a box-shadow. */
	--drop-rest: drop-shadow(0.5px 1px 1px oklch(var(--shadow-color) / 0.12))
		drop-shadow(2px 4px 4px oklch(var(--shadow-color) / 0.1))
		drop-shadow(4px 8px 8px oklch(var(--shadow-color) / 0.08));
	--drop-lifted: drop-shadow(1px 2px 2px oklch(var(--shadow-color) / 0.08))
		drop-shadow(4px 8px 8px oklch(var(--shadow-color) / 0.07))
		drop-shadow(16px 32px 32px oklch(var(--shadow-color) / 0.06));

	--ease-drop: cubic-bezier(0.16, 1, 0.3, 1);
	--ease-settle: linear(
		0,
		0.049,
		0.156,
		0.283,
		0.408,
		0.522,
		0.62,
		0.702,
		0.769,
		0.822,
		0.864,
		0.897,
		0.922,
		0.941,
		0.956,
		0.967,
		0.976,
		0.982,
		0.987,
		0.99,
		1
	);
	--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
	--dur-press: 120ms;
	--dur-state: 150ms;
	--dur-drop: 560ms;
	--dur-settle: 640ms;
	--drop-distance: 24px;
	--drop-turn-max: 4deg;

	/* The phone's scale: the kit draws a 412 by 866 point device around a 390 by 844 point
	 * screen, and the page draws it at --k of that size. A plain number, set per breakpoint,
	 * so the frame, the still and the live screens all size from it without a script. */
	--k: 0.62;
	/* How much of the phone shows above the signup clipping on phones: enough of the screen
	 * (about its top 645 points) that the fields Brook prints are in view. */
	--peek: 0.745;

	color-scheme: light dark;
	accent-color: var(--action);
}

/* The night: a warm night, the board in night kraft keeping 10 percent of its fibre, paper
 * one step darker than the board, light ink, and the strip turned light with night type.
 * Depth moves from shadow to a lighter edge over a brown-black shadow, never a black one. */
@media (prefers-color-scheme: dark) {
	:root:not([data-mode="light"]) {
		--kraft: oklch(0.27 0.045 62);
		--kraft-light: oklch(0.34 0.045 62);
		--kraft-deep: oklch(0.22 0.04 62);
		--kraft-veil: oklch(0.27 0.045 62 / 0.9);
		--paper: oklch(0.2 0.012 60);
		--paper-shade: oklch(0.25 0.012 60);
		--ink: oklch(0.95 0.005 60);
		--ink-soft: oklch(0.72 0.012 60);
		--action: oklch(0.95 0.005 60);
		--action-press: oklch(0.85 0.005 60);
		--action-label: oklch(0.2 0.012 60);
		--tint: oklch(0.34 0.04 70);
		--error: oklch(0.72 0.15 25);
		--tape-kraft: oklch(0.45 0.05 70 / 0.7);
		--footer-ink: var(--ink);
		--device: oklch(0.1 0.01 60);
		--device-edge: oklch(0.45 0.03 60);
		--device-inner: oklch(0.06 0.01 60);
		--device-rim: oklch(0.4 0.025 60);

		--shadow-color: 0.08 0.03 60;
		--edge-light: oklch(0.4 0.02 60);
		--shadow-rest:
			0 0 0 1px var(--edge-light), 1px 2px 3px oklch(var(--shadow-color) / 0.5),
			3px 6px 10px oklch(var(--shadow-color) / 0.35);
		--shadow-lifted:
			0 0 0 1px var(--edge-light), 1px 2px 4px oklch(var(--shadow-color) / 0.5),
			4px 10px 20px oklch(var(--shadow-color) / 0.4);
		--shadow-tape: 0.5px 1px 1.5px oklch(var(--shadow-color) / 0.5);
		/* The kit's night depth on every clipping (its 1px lighter ring, then the brown-black
		 * drop). A torn piece's mask would clip a box-shadow, so the ring is four unblurred 1px
		 * drop shadows, one per side, chained on the wrapper: it follows the tear. */
		--edge-ring: drop-shadow(-1px 0 0 var(--edge-light))
			drop-shadow(1px 0 0 var(--edge-light))
			drop-shadow(0 -1px 0 var(--edge-light))
			drop-shadow(0 1px 0 var(--edge-light));
		--drop-rest: var(--edge-ring)
			drop-shadow(1px 2px 2px oklch(var(--shadow-color) / 0.5))
			drop-shadow(3px 6px 8px oklch(var(--shadow-color) / 0.4));
		--drop-lifted: var(--edge-ring)
			drop-shadow(2px 4px 4px oklch(var(--shadow-color) / 0.5))
			drop-shadow(6px 12px 18px oklch(var(--shadow-color) / 0.4));
	}
}

/* The visitor's own choice (the light or dark square beside the phone, public/demo.js): the
 * same night under data-mode="dark" on the root, whatever the system says, and the system's
 * night yields to a chosen day. test/node/page-palette.test.ts keeps the two blocks equal. */
:root[data-mode="dark"] {
	--kraft: oklch(0.27 0.045 62);
	--kraft-light: oklch(0.34 0.045 62);
	--kraft-deep: oklch(0.22 0.04 62);
	--kraft-veil: oklch(0.27 0.045 62 / 0.9);
	--paper: oklch(0.2 0.012 60);
	--paper-shade: oklch(0.25 0.012 60);
	--ink: oklch(0.95 0.005 60);
	--ink-soft: oklch(0.72 0.012 60);
	--action: oklch(0.95 0.005 60);
	--action-press: oklch(0.85 0.005 60);
	--action-label: oklch(0.2 0.012 60);
	--tint: oklch(0.34 0.04 70);
	--error: oklch(0.72 0.15 25);
	--tape-kraft: oklch(0.45 0.05 70 / 0.7);
	--footer-ink: var(--ink);
	--device: oklch(0.1 0.01 60);
	--device-edge: oklch(0.45 0.03 60);
	--device-inner: oklch(0.06 0.01 60);
	--device-rim: oklch(0.4 0.025 60);

	--shadow-color: 0.08 0.03 60;
	--edge-light: oklch(0.4 0.02 60);
	--shadow-rest:
		0 0 0 1px var(--edge-light), 1px 2px 3px oklch(var(--shadow-color) / 0.5),
		3px 6px 10px oklch(var(--shadow-color) / 0.35);
	--shadow-lifted:
		0 0 0 1px var(--edge-light), 1px 2px 4px oklch(var(--shadow-color) / 0.5),
		4px 10px 20px oklch(var(--shadow-color) / 0.4);
	--shadow-tape: 0.5px 1px 1.5px oklch(var(--shadow-color) / 0.5);
	/* The kit's night depth on every clipping (its 1px lighter ring, then the brown-black
	 * drop). A torn piece's mask would clip a box-shadow, so the ring is four unblurred 1px
	 * drop shadows, one per side, chained on the wrapper: it follows the tear. */
	--edge-ring: drop-shadow(-1px 0 0 var(--edge-light))
		drop-shadow(1px 0 0 var(--edge-light))
		drop-shadow(0 -1px 0 var(--edge-light))
		drop-shadow(0 1px 0 var(--edge-light));
	--drop-rest: var(--edge-ring)
		drop-shadow(1px 2px 2px oklch(var(--shadow-color) / 0.5))
		drop-shadow(3px 6px 8px oklch(var(--shadow-color) / 0.4));
	--drop-lifted: var(--edge-ring)
		drop-shadow(2px 4px 4px oklch(var(--shadow-color) / 0.5))
		drop-shadow(6px 12px 18px oklch(var(--shadow-color) / 0.4));
}

:root[data-mode="dark"] {
	color-scheme: dark;
}

:root[data-mode="light"] {
	color-scheme: light;
}

/* Reduced motion, by name (DESIGN.md): the lift and settle on success and the tape press
 * become a fade at the resting place; the spinner slows; the demo is its still. */
@media (prefers-reduced-motion: reduce) {
	:root {
		--drop-distance: 0px;
		--drop-turn-max: 0deg;
		--dur-drop: 160ms;
		--dur-settle: 0ms;
	}
}

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

::selection {
	background: var(--tint);
	color: var(--ink);
}

html {
	-webkit-text-size-adjust: 100%;
	scrollbar-color: var(--kraft-deep) var(--kraft);
}

body {
	margin: 0;
	min-height: 100svh;
	color: var(--ink);
	font-family: var(--font-text);
	font-size: var(--text-base);
	font-weight: var(--weight-text);
	line-height: var(--leading-text);
	caret-color: var(--ink);
	/* The kraft board: flat color, a fine fiber grain and a broad mottle, both faint. The grain's
	 * alpha (0.38) keeps its darkest fibers at 4.5:1 or better behind ink (#9 measured the
	 * rendered pixels; at 0.55 single fibers fell to 4.3:1). At night the veil on top lets
	 * 10 percent of the fibre through, as the kit's night kraft does. */
	background-color: var(--kraft);
	background-image:
		linear-gradient(var(--kraft-veil), var(--kraft-veil)),
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85 0.35' numOctaves='3' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.23 0 0 0 0 0.15 0 0 0 0 0.08 0 0 0 0.38 -0.2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"),
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='m' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.005' numOctaves='2' seed='9' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.86 0 0 0 0 0.74 0 0 0 0 0.6 0 0 0 0.5 -0.18'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23m)'/%3E%3C/svg%3E");
	-webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
p,
ol,
ul,
figure {
	margin: 0;
}

ol,
ul {
	padding: 0;
}

/* A text action is ink at 600 with a 2px underline (DESIGN.md), never a color. */
a {
	color: var(--ink);
	font-weight: var(--weight-strong);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.2em;
}

strong {
	font-weight: var(--weight-strong);
}

:focus-visible {
	outline: 2px solid var(--ink);
	outline-offset: 2px;
}

.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* Layout: phone first. One reading column: the phone, then the signup clipping laid over the
 * phone's lower part, then the rest of the story. */
main {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas: "demo" "signup" "how" "proof" "founding" "faq";
	row-gap: var(--space-12);
	padding: max(var(--space-3), env(safe-area-inset-top))
		max(var(--gutter), env(safe-area-inset-right)) var(--space-16)
		max(var(--gutter), env(safe-area-inset-left));
	overflow-x: clip;
}

/* On phones the wordmark sits on the board beside the phone, where the kraft is free, so the
 * phone and the form both fit the first screen. */
.masthead {
	position: absolute;
	top: max(var(--space-4), env(safe-area-inset-top));
	left: max(var(--gutter), env(safe-area-inset-left));
}

/* The logo (DESIGN.md "Logo"), drawn from the display face's own outlines: its letters are
 * the size the face would set at this font-size, and it takes the text colour. */
.wordmark {
	font-size: 1.75rem;
	line-height: 1;
}

.wordmark svg {
	display: block;
	width: auto;
	height: 0.79em;
}

/* The app demo (#27). The phone is drawn here, not by the kit, so it paints with the page:
 * the bezel and the island from the kit's own measures (public/kit/kit.css, .bk-device),
 * every size a multiple of --k. Text that must be read is never rotated, and the phone's
 * screen is text, so the phone sits square. */
.demo {
	grid-area: demo;
	position: relative;
	/* The phone is a picture of the app: its words are not the page's to select. */
	user-select: none;
	-webkit-user-select: none;
	display: grid;
	justify-items: end;
	/* The signup clipping covers the phone's lower part. */
	margin-bottom: calc(
		-1 *
		var(--space-12) -
		866px *
		var(--k) *
		(1 - var(--peek))
	);
	min-width: 0;
}

.device {
	position: relative;
	width: calc(412px * var(--k));
	height: calc(866px * var(--k));
	padding: calc(11px * var(--k));
	border-radius: calc(62px * var(--k));
	background: var(--device);
	box-shadow:
		0 0 0 1px var(--device-rim),
		inset 0 0 0 calc(1.5px * var(--k)) var(--device-edge),
		inset 0 0 0 calc(5px * var(--k)) var(--device-inner),
		1px 2px 2px oklch(var(--shadow-color) / 0.12),
		4px 8px 8px oklch(var(--shadow-color) / 0.12),
		10px 20px 22px oklch(var(--shadow-color) / 0.12),
		22px 44px 48px oklch(var(--shadow-color) / 0.14);
}

.device-screen {
	position: relative;
	width: calc(390px * var(--k));
	height: calc(844px * var(--k));
	overflow: hidden;
	border-radius: calc(51px * var(--k));
	/* The same clip as the kit's device (kit.css): it holds over composited layers too. */
	clip-path: inset(0 round calc(51px * var(--k)));
	background: var(--kraft);
}

.device-island {
	position: absolute;
	top: calc(22px * var(--k));
	left: 50%;
	width: calc(124px * var(--k));
	height: calc(36px * var(--k));
	translate: -50% 0;
	border-radius: calc(18px * var(--k));
	background: oklch(0.08 0 0);
}

.demo-still {
	display: block;
	width: 100%;
	height: 100%;
}

/* demo.js mounts one kit screen per step of the loop here, each a 390 by 844 point screen
 * scaled to the phone; only the one playing is shown, and the screens cut from one to the
 * next like a video edit. The live demo fades in over the still once the kit is ready, at the
 * still's own frame, so nothing jumps. The fade also keeps the still as the page's largest
 * contentful paint: measured with Lighthouse 13.5.0 on 2026-10-10, an instant swap made the
 * kit's screen the LCP element at about 6.5 s on the throttled phone profile, against 2.0 s. */
.demo-live {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity var(--dur-state) var(--ease-out);
}

.demo[data-live] .demo-live {
	opacity: 1;
}

.demo-live > .bk-screen {
	position: absolute;
	top: 0;
	left: 0;
	transform: scale(var(--k));
	transform-origin: 0 0;
	opacity: 0;
}

.demo-live > .bk-screen.is-shown {
	opacity: 1;
}

/* Pause and play (WCAG 2.2.2: the demo moves for more than five seconds). A small square of
 * paper held against the phone's left side, near its top, with an ink glyph: much lighter than the strip. Its
 * name stays "Pause the demo"; aria-pressed says whether that is on. */
.demo-toggle,
.mode-toggle {
	position: absolute;
	top: calc(64px * var(--k));
	/* On the board beside the phone's left side, clear of the bezel (#41 critic: straddling
	 * the bezel read as a UI accident): the phone sits at the right of the figure on phones. */
	right: calc(412px * var(--k) + 0.5rem);
	z-index: 1;
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	color: var(--ink);
	background: var(--paper);
	border: 0;
	border-radius: var(--radius-paper);
	box-shadow: var(--shadow-rest);
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: box-shadow var(--dur-press) var(--ease-out);
}

.demo-toggle[hidden],
.mode-toggle[hidden] {
	display: none;
}

.demo-toggle svg,
.mode-toggle svg {
	fill: currentColor;
}

/* Light or dark, the visitor's own choice (public/demo.js): a second paper square under the
 * pause square, in the same column on the board. Its glyph is a disc half inked: the day's
 * half by day, the night's half at night. Its name stays "Dark mode"; aria-pressed says
 * whether that is on. */
.mode-toggle {
	top: calc(64px * var(--k) + 2.75rem + 0.5rem);
}

.mode-toggle[aria-pressed="true"] svg {
	transform: rotate(180deg);
}

.demo-toggle .icon-play,
.demo-toggle[aria-pressed="true"] .icon-pause {
	display: none;
}

.demo-toggle[aria-pressed="true"] .icon-play {
	display: block;
}

/* Pressed: the visitor paused it. The scrap lies flatter on the board. */
.demo-toggle[aria-pressed="true"] {
	background: var(--paper-shade);
	box-shadow: var(--shadow-tape);
}

@media (hover: hover) {
	.demo-toggle:hover,
	.mode-toggle:hover {
		box-shadow: var(--shadow-lifted);
	}
}

/* Reduced motion keeps the still, even if a script already started the demo. */
@media (prefers-reduced-motion: reduce) {
	.demo-live,
	.demo-toggle {
		display: none;
	}
}

/* The signup clipping: the headline, the line of copy and the form on one piece of paper,
 * torn along the top where it lies over the phone and along the bottom. Its torn edges are
 * a mask, so its shadow is a filter on the wrapper. */
.signup {
	grid-area: signup;
	position: relative;
	z-index: 1;
	filter: var(--drop-rest);
	max-width: 34rem;
}

.signup-paper {
	display: grid;
	/* The torn edges take 10 to 13px of each end, so the padding clears them. */
	padding: 1.625rem var(--space-4) 1.875rem;
	background: var(--paper);
	mask:
		url(/img/torn-top.svg) top / 100% 14px no-repeat,
		linear-gradient(#000 0 0) center / 100% calc(100% - 26px) no-repeat,
		url(/img/torn-a.svg) bottom / 100% 14px no-repeat;
}

h1 {
	font-family: var(--font-display);
	font-weight: 400;
	font-size: clamp(2.375rem, 1.6rem + 3.2vw, 4.25rem);
	line-height: var(--leading-display);
	letter-spacing: var(--tracking-display);
	text-wrap: balance;
}

.lead {
	margin-top: var(--space-2);
	max-width: 38ch;
	text-wrap: pretty;
}

.signup-form {
	margin-top: var(--space-4);
}

.signup-heading {
	font-family: var(--font-display);
	font-weight: 400;
	font-size: var(--display-sm);
	line-height: var(--leading-display);
	letter-spacing: var(--tracking-display);
	text-wrap: balance;
}

.signup-intro {
	margin-top: var(--space-2);
	text-wrap: pretty;
}

form {
	display: grid;
}

.field-label {
	font-size: 0.9375rem;
	font-weight: var(--weight-strong);
	margin-bottom: var(--space-1);
}

input[type="email"] {
	width: 100%;
	min-height: 3rem;
	padding: var(--space-2) var(--space-3);
	font: inherit;
	font-size: max(1rem, var(--text-base));
	color: var(--ink);
	background: var(--paper-shade);
	border: 1.5px solid var(--ink-soft);
	caret-color: var(--ink);
	border-radius: var(--radius-field);
	transition: border-color var(--dur-state) var(--ease-out);
}

input[type="email"][aria-invalid="true"] {
	border-color: var(--error);
}

.field-error {
	margin-top: var(--space-2);
	font-size: 0.9375rem;
	font-weight: 500;
	color: var(--error);
}

.field-error:empty {
	display: none;
}

/* The primary action is the label strip (DESIGN.md): at its label's width, ink with paper
 * type by day and light ink with night type at night, with torn short ends of a fixed 8px
 * (the kit's shape, public/img/strip-end-*.svg, so a short strip and a long one tear the
 * same). The strip is drawn on ::before, so its mask never clips the focus ring on the
 * button itself. 48px tall on the page: the one thing to press, in thumb reach. */
.tape-button {
	position: relative;
	z-index: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	justify-self: start;
	min-height: var(--tape-height);
	margin-top: var(--space-3);
	padding: 0 var(--space-8);
	font: inherit;
	font-size: 1.0625rem;
	font-weight: var(--weight-strong);
	color: var(--action-label);
	text-decoration: none;
	background: none;
	border: 0;
	border-radius: var(--radius-paper);
	cursor: pointer;
	filter: drop-shadow(0.5px 1px 1.5px oklch(var(--shadow-color) / 0.25));
	-webkit-tap-highlight-color: transparent;
}

.tape-button::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--action);
	mask:
		url(/img/strip-end-l.svg) left top / 8px 100% no-repeat,
		linear-gradient(#000 0 0) 8px 0 / calc(100% - 16px) 100% no-repeat,
		url(/img/strip-end-r.svg) right top / 8px 100% no-repeat;
	transition: background-color var(--dur-press) var(--ease-out);
}

.tape-label {
	position: relative;
}

@media (hover: hover) {
	.tape-button:hover::before {
		background: var(--action-press);
	}
}

.tape-button:active::before {
	background: var(--action-press);
}

.spinner {
	display: none;
	width: 0.95rem;
	height: 0.95rem;
	border: 2px solid color-mix(in oklch, var(--action-label) 35%, transparent);
	border-top-color: var(--action-label);
	border-radius: 50%;
	animation: spin 700ms linear infinite;
}

.tape-button[aria-busy="true"] .spinner {
	display: block;
}

@keyframes spin {
	to {
		rotate: 1turn;
	}
}

@media (prefers-reduced-motion: reduce) {
	.spinner {
		animation-duration: 1600ms;
	}
}

.form-note {
	margin-top: var(--space-3);
	max-width: 46ch;
	font-size: var(--text-sm);
	color: var(--ink-soft);
	text-wrap: pretty;
}

/* States. data-state on <main> is set by the Worker without JavaScript and by signup.js with it. */
.signup-joined {
	display: none;
	position: relative;
	margin-top: var(--space-6);
	/* Focused only by script, to announce the result; it is not a control, so it draws no ring. */
	outline: none;
}

main[data-state="joined"] .signup-form {
	display: none;
}

/* Once joined, the founding place is empty, and without a checkout link the Worker removes
 * it (data-offer="none"): its row goes too, so no double gap is left. */
main[data-state="joined"],
main[data-offer="none"] {
	grid-template-areas: "demo" "signup" "how" "proof" "faq";
}

main[data-state="joined"] .signup-joined {
	display: block;
}

.offer-slot:empty {
	display: none;
}

/* The founding-member offer: a second, smaller clipping, cut from the shaded back of the
 * paper with its own torn edge (torn-b). Inside the success screen it reads second (a smaller
 * display line, a flat shade, no tape of its own); in its own section on the page it is a
 * paper clipping on the board. Its button is the same label strip as the form's. The Worker
 * writes it only when the checkout link is set (docs/preorder.md). */
.offer {
	display: grid;
	margin-top: var(--space-6);
	padding: var(--space-4) var(--space-4) calc(var(--space-4) + 12px);
	background: var(--paper-shade);
	border-radius: var(--radius-paper) var(--radius-paper) 0 0;
	mask:
		linear-gradient(#000 0 0) top / 100% calc(100% - 13px) no-repeat,
		url(/img/torn-b.svg) bottom / 100% 14px no-repeat;
}

.offer-heading {
	margin: 0;
	font-family: var(--font-display);
	font-weight: 400;
	font-size: 1.625rem;
	line-height: 1.1;
	letter-spacing: var(--tracking-display);
	text-wrap: balance;
}

/* Spots left (#23), read from the founding members at page time. The count takes the label
 * weight, in tabular figures since it changes. The full state keeps the same lines and has
 * no button. */
.offer-spots {
	margin-top: var(--space-1);
}

/* Tabular figures on the count only: in Schibsted Grotesk they also widen the full stop. */
.offer-count {
	font-weight: var(--weight-strong);
	font-variant-numeric: tabular-nums;
}

.offer-terms {
	margin-top: var(--space-2);
	max-width: 40ch;
	text-wrap: pretty;
}

/* The refund and the reassurance sit on their own line, before the ask. */
.offer-terms + .offer-terms {
	margin-top: var(--space-1);
}

/* The strip at its label's width, as on the form. */
.offer-button {
	text-align: center;
}

.offer-note {
	margin-top: var(--space-3);
	font-size: var(--text-sm);
	color: var(--ink-soft);
	text-wrap: pretty;
}

/* The settle, played by signup.js on success: the clipping lifts a little from where it is,
 * slightly turned, then lands flat with its shadow tightening. */
.signup.is-settling {
	animation:
		lift-settle var(--dur-settle) var(--ease-settle),
		shadow-settle var(--dur-settle) var(--ease-settle);
}

@keyframes lift-settle {
	0% {
		translate: 0 0;
		rotate: 0deg;
	}
	30% {
		translate: 0 calc(-0.4 * var(--drop-distance));
		rotate: calc(-0.35 * var(--drop-turn-max));
	}
	100% {
		translate: 0 0;
		rotate: 0deg;
	}
}

@keyframes shadow-settle {
	30% {
		filter: var(--drop-lifted);
	}
}

@media (prefers-reduced-motion: reduce) {
	.signup.is-settling {
		animation: fade-in var(--dur-drop) var(--ease-out);
	}
}

@keyframes fade-in {
	from {
		opacity: 0.4;
	}
}

/* The story under the form: paper clippings on the board, one column on phones, each torn
 * along a different edge (the how-to at its foot, the proof at its foot under its tape, the
 * questions along the top). The tear is a mask on the sheet, so the shadow is a filter on
 * the section around it. */
.how,
.proof,
.faq {
	position: relative;
	filter: var(--drop-rest);
}

.sheet {
	padding: var(--space-6) var(--space-4);
	background: var(--paper);
	border-radius: var(--radius-paper);
}

.how .sheet {
	padding-bottom: 2.25rem;
	mask:
		linear-gradient(#000 0 0) top / 100% calc(100% - 13px) no-repeat,
		url(/img/torn-a.svg) bottom / 100% 14px no-repeat;
}

.proof .sheet {
	padding-bottom: 2.25rem;
	mask:
		linear-gradient(#000 0 0) top / 100% calc(100% - 13px) no-repeat,
		url(/img/torn-b.svg) bottom / 100% 14px no-repeat;
}

.faq .sheet {
	padding-top: 2.25rem;
	mask:
		url(/img/torn-top.svg) top / 100% 14px no-repeat,
		linear-gradient(#000 0 0) bottom / 100% calc(100% - 13px) no-repeat;
}

.how h2,
.proof h2,
.faq h2 {
	font-family: var(--font-display);
	font-weight: 400;
	font-size: var(--display-sm);
	line-height: var(--leading-display);
	letter-spacing: var(--tracking-display);
	text-wrap: balance;
}

h3 {
	font-size: var(--text-base);
	font-weight: var(--weight-strong);
	line-height: 1.35;
}

/* How saves get in: an ordered method, like the steps on a recipe clipping. The numbers are
 * the sequence itself, set in the display face beside each step. */
.how {
	grid-area: how;
}

.steps {
	display: grid;
	gap: var(--space-6);
	margin-top: var(--space-6);
	list-style: none;
	counter-reset: step;
}

.step {
	display: grid;
	grid-template-columns: 2rem minmax(0, 1fr);
	align-content: start;
	column-gap: var(--space-3);
	counter-increment: step;
}

.step::before {
	content: counter(step);
	grid-row: span 3;
	font-family: var(--font-display);
	font-size: 2.25rem;
	line-height: 0.9;
}

.step > * {
	grid-column: 2;
}

.step p {
	margin-top: var(--space-1);
	text-wrap: pretty;
}

/* Brook in the share sheet, cut from the kit's share screen (demo.js mounts it at its
 * `sheet` state and this frame shows only the row of apps). A picture, so it is hidden from
 * screen readers; the step's words say the same. Empty without the script. */
.step-shot {
	--shot-k: 0.78;
	/* Whole apps of the row, Brook first, with the row's own 20 point inset on both sides: the
	 * kit's tiles are 62 points wide on an 84 point pitch from 20 points in, so four end at
	 * 334 and the window is 354 (the old 332 cut Notes and left no right inset, #41). Narrow
	 * phones show three (Brook, Messages, Mail), as a share row scrolls, rather than shrink
	 * the sheet. Never clamped to the column: a clamp cuts a tile. */
	--shot-w: 354px;
	position: relative;
	width: calc(var(--shot-w) * var(--shot-k));
	height: calc(112px * var(--shot-k));
	margin-top: var(--space-3);
	overflow: hidden;
	border-radius: var(--radius-paper);
	box-shadow: var(--shadow-rest);
}

/* Four whole apps need 276px at 0.78; the step's column is the screen less 108px (the page's
 * gutters, the clipping's padding and the step number), so phones up to 385px show three. */
@media (max-width: 24.0625rem) {
	.step-shot {
		--shot-w: 270px;
	}
}

.step-shot:empty {
	display: none;
}

.step-shot > .bk-screen {
	position: absolute;
	top: 0;
	left: 0;
	transform: scale(var(--shot-k)) translateY(-582px);
	transform-origin: 0 0;
}

/* The proof: the eval's numbers in sentences, the count at the label weight. A strip of
 * kraft tape holds the clipping to the board (tape on at most a third of the pieces,
 * DESIGN.md): translucent, so the paper's edge and the board show through it, its torn ends
 * the committed tape shape, lying over the clipping's top edge at an angle like a strip
 * pressed down by hand, with the faint shadow real tape throws. */
.proof {
	grid-area: proof;
}

.proof::before {
	content: "";
	position: absolute;
	z-index: 1;
	top: -0.85rem;
	left: 1.25rem;
	width: 7.25rem;
	height: 1.75rem;
	background: var(--tape-kraft);
	rotate: -3.5deg;
	mask: url(/img/tape-ends.svg) 0 0 / 100% 100% no-repeat;
	filter: drop-shadow(0.5px 1px 1px oklch(var(--shadow-color) / 0.3));
}

.proof p {
	margin-top: var(--space-3);
	max-width: 60ch;
	text-wrap: pretty;
}

.proof-results {
	display: grid;
	gap: var(--space-3);
	margin-top: var(--space-4);
	padding-left: var(--space-4);
	max-width: 60ch;
	border-left: 1px solid var(--ink-soft);
	list-style: none;
}

.proof-results li {
	text-wrap: pretty;
}

.proof-results strong {
	font-variant-numeric: tabular-nums;
}

.proof-scope {
	font-size: var(--text-sm);
	color: var(--ink-soft);
}

.proof-scope a {
	display: inline-block;
	font-weight: var(--weight-strong);
}

/* The founding offer in its own place on the page, after the proof. On the board it is a
 * white clipping; inside the success screen it keeps the paper shade. */
.founding {
	grid-area: founding;
	filter: var(--drop-rest);
	max-width: 34rem;
}

/* Once joined, the offer has moved into the success screen; this place stays empty. */
main[data-state="joined"] .founding {
	display: none;
}

.founding .offer {
	margin-top: 0;
	padding: var(--space-6) var(--space-4) calc(var(--space-6) + 12px);
	background: var(--paper);
}

.founding .offer-heading {
	font-size: var(--display-sm);
}

/* Questions: each one a short heading and its answer. */
.faq {
	grid-area: faq;
}

.faq-list {
	display: grid;
	gap: var(--space-6);
	margin-top: var(--space-6);
}

.qa p {
	margin-top: var(--space-1);
	max-width: 60ch;
	text-wrap: pretty;
}

.qa a,
.footer a {
	overflow-wrap: anywhere;
}

/* The board's deep edge carries only paper type by day (5.45:1) and light ink at night
 * (DESIGN.md). */
.footer {
	display: grid;
	gap: var(--space-2);
	padding: var(--space-8) max(var(--gutter), env(safe-area-inset-right))
		max(var(--space-8), env(safe-area-inset-bottom))
		max(var(--gutter), env(safe-area-inset-left));
	font-size: var(--text-sm);
	color: var(--footer-ink);
	background: var(--footer-ground);
}

.footer p {
	max-width: 66ch;
	text-wrap: pretty;
}

.footer a {
	color: var(--footer-ink);
}

.footer :focus-visible {
	outline-color: var(--footer-ink);
}

/* The sticky way back to the form, on phones, once the form has left the screen (signup.js).
 * A strip of paper along the bottom edge holding the same tape: one action, never a second
 * form, and never on screen with the form or the offer, so one strip at a time. */
.sticky-cta {
	position: fixed;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 10;
	display: grid;
	padding: calc(var(--space-2) + 10px)
		max(var(--gutter), env(safe-area-inset-right))
		max(var(--space-3), env(safe-area-inset-bottom))
		max(var(--gutter), env(safe-area-inset-left));
	background: var(--paper);
	filter: drop-shadow(0 -2px 6px oklch(var(--shadow-color) / 0.16));
	mask:
		url(/img/torn-top.svg) top / 100% 14px no-repeat,
		linear-gradient(#000 0 0) bottom / 100% calc(100% - 13px) no-repeat;
	transition:
		translate var(--dur-state) var(--ease-out),
		opacity var(--dur-state) var(--ease-out);
}

.sticky-cta[hidden] {
	display: none;
}

.sticky-cta .tape-button {
	justify-self: center;
	margin-top: 0;
}

/* Phones: the footer ends above where the bar sits (its 18px top, the 48px strip and its
 * bottom inset), whether or not the bar has appeared yet: padding added only once the bar
 * shows left a visitor already at the foot with the footer under it (#41 live critic). */
@media (max-width: 39.99rem) {
	.footer {
		padding-bottom: calc(
			var(--space-8) +
			18px +
			var(--tape-height) +
			max(var(--space-3), env(safe-area-inset-bottom))
		);
	}
}

@starting-style {
	.sticky-cta {
		opacity: 0;
		translate: 0 0.75rem;
	}
}

@media (prefers-reduced-motion: reduce) {
	@starting-style {
		.sticky-cta {
			translate: 0 0;
		}
	}
}

/* Phone sizes: the phone as large as fits with the form's button still on an 844-point
 * screen. */
/* The narrowest phones (320 to 374px): a smaller phone, so the board beside it still holds
 * the paper squares clear of the bezel and the screen's edge. */
@media (max-width: 23.4374rem) {
	:root {
		--k: 0.54;
	}
}

/* Phones under 414px: the wordmark a step smaller, so it ends clear of the bezel. */
@media (max-width: 25.8749rem) {
	.wordmark {
		font-size: 1.5rem;
	}
}

/* The masthead's logo: the whole logo, or on phones under 414px the mark alone, since the
 * word would run under the bezel there. The footer keeps the whole logo. */
.wordmark .wordmark-mark {
	display: none;
	height: 1.1em;
}

@media (max-width: 25.8749rem) {
	.masthead .wordmark-full {
		display: none;
	}

	.masthead .wordmark-mark {
		display: block;
	}
}

@media (min-width: 23.4375rem) {
	:root {
		--k: 0.7;
	}
}

@media (min-width: 25.875rem) {
	:root {
		--k: 0.74;
	}
}

/* Short phone screens, such as an in-app browser under its own bars (390 by 664, #41): the
 * form's button must still be on the first screen. The phone shows less of itself (its top
 * 420 points or so: a search result's title and first fields, the first rows of Saved) and
 * the headline drops a step; nothing else moves. */
@media (max-width: 39.99rem) and (max-height: 46rem) {
	:root {
		--peek: 0.5;
	}
	h1 {
		font-size: 2.125rem;
	}
}

/* Wider phones and small tablets. */
@media (min-width: 40rem) {
	:root {
		--k: 0.8;
		--peek: 0.7;
	}
	main {
		padding-inline: var(--space-8);
	}
	.lead {
		font-size: var(--text-lg);
		/* Inherited anyway; stated so the detector reads the larger lead at 1.5, not at the
		 * body's line height in pixels. */
		line-height: 1.5;
	}
	.signup-paper {
		padding: 2.125rem var(--space-6) 2.375rem;
	}
	/* The field and the tape keep one width: the tape runs the field's width, as on phones. */
	.signup form {
		max-width: 24rem;
	}
	.sheet {
		padding: var(--space-8);
	}
	.how .sheet,
	.proof .sheet {
		padding-bottom: 2.75rem;
	}
	.faq .sheet {
		padding-top: 2.75rem;
	}
	.founding .offer {
		padding: var(--space-8) var(--space-8) calc(var(--space-8) + 12px);
	}
	.sticky-cta {
		display: none;
	}
}

/* Desktop: its own composition. The clipping on the left, the whole phone on the right, on
 * the same board; below, the story set off-center, so the page is not one centered column. */
@media (min-width: 60rem) {
	:root {
		--k: 0.78;
	}
	main {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		grid-template-areas:
			"mast demo"
			"signup demo"
			"how how"
			"proof founding"
			"faq faq";
		grid-template-rows: auto 1fr;
		column-gap: clamp(var(--space-8), 5vw, var(--space-16));
		row-gap: var(--space-12);
		max-width: 80rem;
		margin-inline: auto;
		padding: var(--space-8) clamp(var(--space-8), 5vw, var(--space-16))
			var(--space-24);
	}
	main[data-state="joined"],
	main[data-offer="none"] {
		grid-template-areas:
			"mast demo"
			"signup demo"
			"how how"
			"proof proof"
			"faq faq";
	}
	.masthead {
		position: static;
		grid-area: mast;
	}
	.demo {
		align-self: start;
		justify-items: start;
		margin: 0;
		padding-left: 4rem;
	}
	/* On desktop the phone sits at the figure's left, after its 4rem of board. */
	.demo-toggle,
	.mode-toggle {
		right: auto;
		left: calc(4rem - 2.75rem - 0.5rem);
	}
	.signup {
		align-self: center;
		margin-top: calc(-1 * var(--space-8));
	}
	.how .sheet {
		display: grid;
		grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
		column-gap: var(--space-12);
		padding: var(--space-12) var(--space-12) 3.5rem;
	}
	/* The method stays a method: one column of steps beside the heading, not three columns. */
	.steps {
		max-width: 36rem;
		margin-top: 0;
	}
	.proof {
		align-self: start;
	}
	.proof .sheet {
		padding: var(--space-12) var(--space-12) 3.5rem;
	}
	.founding {
		align-self: center;
	}
	.faq .sheet {
		display: grid;
		grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
		column-gap: var(--space-12);
		padding: 3.5rem var(--space-12) var(--space-12);
	}
	.faq-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: var(--space-12);
		row-gap: var(--space-8);
		margin-top: 0;
	}
	/* With the whole row (no offer, or once joined) the proof is laid out like the method and
	 * the questions: its heading in a column of its own beside the text, so the paper is not
	 * half empty (#41 live critic). After the questions' .faq .sheet, so no selector of lower
	 * specificity on a .sheet follows a higher one. */
	main[data-offer="none"] .proof .sheet,
	main[data-state="joined"] .proof .sheet {
		display: grid;
		grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
		align-content: start;
		column-gap: var(--space-12);
	}
	main[data-offer="none"] .proof .sheet > *,
	main[data-state="joined"] .proof .sheet > * {
		grid-column: 2;
	}
	main[data-offer="none"] .proof .sheet > h2,
	main[data-state="joined"] .proof .sheet > h2 {
		grid-column: 1;
		grid-row: 1 / span 4;
	}
	main[data-offer="none"] .proof .sheet > h2 + p,
	main[data-state="joined"] .proof .sheet > h2 + p {
		margin-top: 0;
	}
	.footer {
		grid-template-columns: auto 1fr;
		align-items: baseline;
		column-gap: var(--space-8);
		padding-inline: clamp(var(--space-8), 5vw, var(--space-16));
	}
}

/* A taller desktop screen gets a larger phone, still whole on the first screen. */
@media (min-width: 60rem) and (min-height: 56rem) {
	:root {
		--k: 0.88;
	}
}

@media (min-width: 60rem) and (min-height: 62rem) {
	:root {
		--k: 0.96;
	}
}

/* The eval's write-up (/eval): one long clipping of reading on the board. */
.writeup main {
	display: block;
	max-width: 46rem;
	margin-inline: auto;
	padding-top: var(--space-6);
}

.writeup .masthead {
	position: static;
	margin-bottom: var(--space-6);
}

.writeup .wordmark {
	color: var(--ink);
	text-decoration: none;
}

.writeup-paper {
	padding: var(--space-8) var(--space-4) var(--space-12);
	background: var(--paper);
	border-radius: var(--radius-paper);
	box-shadow: var(--shadow-rest);
}

.writeup-paper h2 {
	margin-top: var(--space-8);
	font-family: var(--font-display);
	font-weight: 400;
	font-size: var(--display-sm);
	line-height: var(--leading-display);
	letter-spacing: var(--tracking-display);
}

.writeup-paper p,
.writeup-paper ul {
	margin-top: var(--space-3);
	max-width: 62ch;
	text-wrap: pretty;
}

.writeup-paper ul {
	display: grid;
	gap: var(--space-2);
	padding-left: 1.25rem;
}

.writeup-paper .lead {
	margin-top: var(--space-4);
	font-size: var(--text-lg);
	line-height: 1.5;
}

.writeup-paper code {
	font-size: 0.9em;
	overflow-wrap: anywhere;
}

.writeup-results strong {
	font-variant-numeric: tabular-nums;
}

.writeup-back {
	margin-top: var(--space-8);
	font-weight: var(--weight-strong);
}

@media (min-width: 40rem) {
	.writeup-paper {
		padding: var(--space-12) var(--space-12) var(--space-16);
	}
}
