/* Tokens copied from kaffa-if0/orders-site/src/lib/tokens.css (the canon) —
   only what this page uses. Control sizing is bumped up from the canon's
   36px/12px for kiosk-sized tap targets on a shared tablet. */
:root {
	color-scheme: light;

	--color-paper: #F7F7F7;
	--color-ink: #262425;
	--color-gray: #5F5F5C;
	--color-surface: #EBEBEB;
	--surface-0: #FFFFFF;
	--color-row-line: rgb(38 36 37 / 0.20);
	--color-red: #C72636;
	--color-control-fill: var(--color-surface);
	--color-control-line: #C7C7C7;

	--font-h01: 'Helvetica Neue', Helvetica, Arial, Inter, ui-sans-serif, system-ui, -apple-system, sans-serif;
	--font-h02: 'PT Serif', Georgia, Charter, ui-serif, serif;

	--fs-14: 14px;
	--fs-20: 20px;
	--fs-28: 28px;

	--pad: 16px;
	--space-half: 8px;
	--space-1: var(--pad);
	--space-2: calc(var(--pad) * 2);
	--space-4: calc(var(--pad) * 4);

	--control-height: 56px;
	--radius-control: 16px;
	--border-control: 1px;
}

@font-face {
	font-family: 'PT Serif';
	src: url('/fonts/pt-serif-400.woff2') format('woff2');
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}

* {
	box-sizing: border-box;
}

html, body {
	margin: 0;
	min-height: 100%;
}

/* A phone turned on its side keeps the type at its size (iOS Safari enlarges
   text in landscape unless told not to; 8 October 2026). */
html {
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

/* The body's gutters (8 October 2026): the page runs edge to edge
   (viewport-fit=cover, index.html), so each side is the larger of its
   gutter and the safe area (an iPhone's notch or Dynamic Island on its side,
   the home indicator, the status bar), the side ones plus 16 of air. The
   gutters themselves are the custom properties, set per width below: 64 32
   120 on the tablet (32 on top on a tablet on its side), 32 32 88 on a
   phone. The tablet's insets are smaller than its gutters, so it does not
   move. `--keyboard` is the room app.js keeps under the content while a
   phone's keyboard is up (fitKeyboard), 0 otherwise. */
body {
	--body-top: var(--space-4);
	--body-side: var(--space-2);
	--body-bottom: calc(var(--space-4) + var(--control-height));
	background: var(--color-paper);
	color: var(--color-ink);
	font-family: var(--font-h01);
	font-size: var(--fs-20);
	line-height: 1.4;
	display: flex;
	flex-direction: column;
	align-items: center;
	min-height: 100vh;
	padding:
		max(var(--body-top), env(safe-area-inset-top, 0px))
		max(var(--body-side), calc(env(safe-area-inset-right, 0px) + var(--space-1)))
		calc(max(var(--body-bottom), calc(env(safe-area-inset-bottom, 0px) + var(--space-2))) + var(--keyboard, 0px))
		max(var(--body-side), calc(env(safe-area-inset-left, 0px) + var(--space-1)));
}

/* The logotype (5 October 2026, the owner: the whole width on a phone, large
   but not radical on a desktop): 200 wide above 480 px (the counter's
   tablet; it was 81), the column's whole width at 480 and under (a phone
   held upright; the body's 32 gutters kept). Its height is reserved from the
   viewBox's ratio (and the img's width and height), so nothing moves when it
   paints. */
.logo {
	display: block;
	flex: none;
	width: 200px;
	max-width: 100%;
	height: auto;
	aspect-ratio: 1857.9 / 732.6;
	margin-bottom: var(--space-4);
}

@media (max-width: 480px) {
	.logo {
		width: 100%;
		margin-bottom: var(--space-2);
	}
}

/* A tablet on its side (an 11-inch iPad in landscape is 834 tall): the air
   above and under the logotype halves, so Continue stays in view as it did
   with the 32-tall logotype. */
@media (min-width: 481px) and (max-height: 900px) {
	body {
		--body-top: var(--space-2);
	}

	.logo {
		margin-bottom: var(--space-2);
	}
}

.screen {
	width: 100%;
	max-width: 480px;
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
}

.screen[hidden] {
	display: none;
}

h1 {
	font-family: var(--font-h02);
	font-size: var(--fs-28);
	font-weight: 400;
	margin: 0;
}

/* The heading is where focus lands when a screen shows (app.js); it is a
   landing spot, not a control, so it draws no ring. */
h1:focus {
	outline: none;
}

/* A long address in a lede ("Code sent to …", the wait screen's, which a
   phone prints whole) breaks rather than pushing the column sideways at 320
   (8 October 2026). */
.lede {
	margin: 0;
	color: var(--color-ink);
	opacity: 0.65;
	overflow-wrap: anywhere;
}

/* The wait screen's lede and the quiet line under it, 8 apart: one block of
   copy, not two of the screen's 32-spaced blocks. */
.lede-group {
	display: flex;
	flex-direction: column;
	gap: var(--space-half);
}

.note {
	margin: 0;
	font-size: var(--fs-14);
	color: var(--color-gray);
}

/* The wait screen's form holds only what shows now and then (an error, the
   Turnstile widget, Try again): with none of them it takes no row, so the
   screen's 32 gap is not doubled above Resend link. */
#form-wait:not(:has(> :not([hidden]):not(.error:empty))) {
	display: none;
}

form {
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
}

/* A hidden form stays hidden (the accept page's, outside its `accept` state): the display above outranks the browser's [hidden]. */
form[hidden] {
	display: none;
}

.field {
	display: flex;
	flex-direction: column;
	gap: var(--space-half);
}

label {
	font-size: var(--fs-14);
}

.optional {
	opacity: 0.5;
}

input {
	height: var(--control-height);
	padding: 0 var(--pad);
	font-size: var(--fs-20);
	font-family: inherit;
	color: var(--color-ink);
	background: var(--surface-0);
	border: var(--border-control) solid var(--color-control-line);
	border-radius: var(--radius-control);
}

input:focus {
	outline: 2px solid var(--color-ink);
	outline-offset: 1px;
}

/* A field with an error under it: the page's one red, on the line and in the words. */
input[aria-invalid='true'] {
	border-color: var(--color-red);
}

button,
.button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	align-self: flex-start;
	box-sizing: border-box;
	text-decoration: none;
	height: var(--control-height);
	padding: 0 var(--space-2);
	font-size: var(--fs-20);
	font-family: inherit;
	font-weight: 400;
	color: var(--surface-0);
	background: var(--color-ink);
	border: none;
	border-radius: var(--radius-control);
	cursor: pointer;
}

/* A hidden button stays hidden (8 October 2026): the display above (7
   October 2026, for the Open Telegram link) outranks the browser's own
   [hidden] rule, which showed Try again on the wait screen, Show my number
   on every welcome and Open Telegram on the tablet. */
button[hidden],
.button[hidden] {
	display: none;
}

button:disabled {
	opacity: 0.45;
	cursor: default;
}

/* A pressed primary (Sending…, Checking…, Creating…) reads, it does not dim: the customer is waiting on it. */
button[aria-busy='true'] {
	opacity: 1;
	cursor: progress;
}

.link-button {
	background: none;
	color: var(--color-ink);
	text-decoration: underline;
	height: auto;
	padding: 8px;
}

/* On a person's own phone the text buttons (Resend link, Resend code, Use a
   different email, Show my number) are a 44 target, Apple's least (8 October
   2026, after the review: a button keeps the browser's `line-height:
   normal`, so the 20 type on 8 of padding made 40). The phone only
   (`data-mode`, set by app.js on /join and /new-client/shared): the counter
   tablet keeps its 40, as it was. The words stay centred (the button's
   inline-flex). */
:root[data-mode='phone'] .link-button {
	min-height: 44px;
}

.error {
	margin: 0;
	color: var(--color-red);
	font-size: var(--fs-14);
	min-height: 1em;
}

.error:empty {
	display: none;
}

/* The general error above a form is a landing spot for focus, not a control. */
.error:focus {
	outline: none;
}

/* The welcome's number and QR in one wrapper that draws no box: its children
   keep the screen's 32 gap; hidden, they all go (app.js, showWelcome). */
.welcome-full {
	display: contents;
}

.welcome-full[hidden] {
	display: none;
}

.client-number {
	font-family: var(--font-h02);
	font-size: calc(var(--fs-28) * 2);
	margin: 0;
}

/* The Telegram link: a QR to scan with one's own phone and the address as
   text, which a long press selects whole; the text breaks anywhere rather
   than pushing the column sideways. */
.tg {
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
}

.tg-lead {
	margin: 0;
}

.qr {
	width: 224px;
	height: 224px;
	padding: var(--space-half);
	background: var(--surface-0);
	border: var(--border-control) solid var(--color-row-line);
	border-radius: var(--radius-control);
}

.qr:empty {
	display: none;
}

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

.tg-link {
	margin: 0;
	font-size: var(--fs-14);
	color: var(--color-gray);
	overflow-wrap: anywhere;
	user-select: all;
	-webkit-user-select: all;
}

/* The idle line, 14 caps: the last 15 s before the kiosk starts over, at
   the foot of the window; any touch or key takes it away. */
.idle {
	position: fixed;
	left: 50%;
	bottom: var(--space-1);
	transform: translateX(-50%);
	margin: 0;
	padding: var(--space-half) var(--space-1);
	background: var(--color-surface);
	border-radius: var(--radius-control);
	font-size: var(--fs-14);
	line-height: 1;
	letter-spacing: 0;
	text-transform: uppercase;
	white-space: nowrap;
	pointer-events: none;
}

.idle[hidden] {
	display: none;
}

/* The honeypot (4 October 2026): off-screen, never focused, hidden from
   screen readers; a bot that fills every input fills it, and the API refuses
   the call. Not display:none, which some bots skip. */
.hp {
	position: absolute;
	left: -10000px;
	top: auto;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* Cloudflare Turnstile, when the API has it on (GET /signup/config): one
   widget in each form, right above the button it guards, the form's 16 gap
   between them; light, as wide as the column. In a column under 300 px the
   widget is scaled to it (app.js, fitCaptcha), never cut. */
.turnstile[hidden] {
	display: none;
}

.turnstile-widget {
	transform-origin: 0 0;
}

/* ── The Terms (12 October 2026; app.js, terms.js) ── */

/* The block over Continue (the sign-up form, /accept-terms): the box and its
   sentence on one row, the error under the sentence, and 8 under them, at the
   column's edge and with no box, the Privacy Policy line, the sentence's
   footnote (8, not the form's 16: on a tablet on its side, 834 tall,
   Continue then ends at 828, in view without Turnstile). */
.agree {
	display: flex;
	flex-direction: column;
	gap: var(--space-half);
}

.agree[hidden] {
	display: none;
}

.agree-row {
	display: grid;
	grid-template-columns: 28px minmax(0, 1fr);
	column-gap: var(--space-1);
	align-items: start;
}

.agree-text {
	display: flex;
	flex-direction: column;
	gap: var(--space-half);
}

/* The sentence is the box's label, at the form's 20 (the fields' labels are
   14): it is what the person agrees to, so it reads as text, not a caption.
   Its 28 line is the box's height, so the box stands on the first line. */
.agree label {
	font-size: var(--fs-20);
	line-height: 28px;
	cursor: pointer;
}

/* The box: drawn 28, square (the canon's checkbox does not float, so it
   takes no radius), the fields' white with an ink line, ink with a white tick
   when ticked; the real checkbox lies over it, invisible, 44 square, so a
   thumb's worth hits it. The tick is the canon's character, as the console's
   .box draws it. */
.check {
	position: relative;
	width: 28px;
	height: 28px;
}

.check input {
	position: absolute;
	top: -8px;
	left: -8px;
	z-index: 1;
	width: 44px;
	height: 44px;
	margin: 0;
	padding: 0;
	border: 0;
	opacity: 0;
	cursor: pointer;
}

.check-box {
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	width: 28px;
	height: 28px;
	background: var(--surface-0);
	border: var(--border-control) solid var(--color-ink);
	color: transparent;
	font-size: var(--fs-20);
	line-height: 1;
}

.check-box::after {
	content: '✓';
}

.check input:checked + .check-box {
	background: var(--color-ink);
	color: var(--surface-0);
}

/* Focus on the box, as on a field (app.js moves it here after "Tick the box"). */
.check input:focus + .check-box {
	outline: 2px solid var(--color-ink);
	outline-offset: 2px;
}

/* Unticked when Continue was pressed: the page's one red on the box's line, as on a field's. */
.check input[aria-invalid='true'] + .check-box {
	border-color: var(--color-red);
}

/* "Terms and Conditions", "Privacy Policy": a link in its sentence, in the
   red and underlined (t2: a colour of its own, not only the underline). The
   padding reaches over the lines next to it and moves nothing (an inline
   box), so a tap has a 44 target at least, whatever the size of the words
   round it (an inline box is its font's 1.15 em or so high: 23.5 at 20, 16.5
   at 14, measured in Chromium). Focus fills the words' own line with the
   controls' grey (a ring round the padding would stand 44 tall). */
.text-link {
	padding-block: calc((46px - 1.15em) / 2);
	color: var(--color-red);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.15em;
	border-radius: 2px;
	background-clip: content-box;
	-webkit-box-decoration-break: clone;
	box-decoration-break: clone;
}

.text-link:focus {
	outline: none;
}

.text-link:focus-visible {
	background-color: var(--color-control-fill);
	text-decoration-thickness: 2px;
}

/* The counter tablet: a long press on a link offers no "Open in new tab" (it
   would leave the kiosk); the press opens the sheet. */
:root:not([data-mode='phone']) #screen-form .text-link {
	-webkit-touch-callout: none;
}

/* A primary whose words may not fit one line ("Confirm email and accept the
   Terms" is 330 wide at 20, a phone's column 311): it grows to two lines,
   centred, 8 over and under them, never under the controls' 56. */
button.long-label {
	height: auto;
	min-height: var(--control-height);
	padding-block: var(--space-half);
	line-height: 1.2;
	text-align: center;
}

/* A button in the controls' grey with ink words (the sheet's Close): the
   canon's ordinary finish beside the one ink primary. */
button.ordinary {
	color: var(--color-ink);
	background: var(--color-control-fill);
}

/* The sheet (terms.js): a modal dialog at the window's foot, the whole width
   on a phone, 720 at most and centred on the tablet, 88 % of the window high
   (its head and buttons stay, the text scrolls between them), on the
   fields' white with the controls' radius on top, over the page dimmed. It
   rises over 400 ms on the canon's movement curve, none with reduced motion;
   it closes with a cut. */
.sheet {
	position: fixed;
	inset: auto 0 0;
	box-sizing: border-box;
	width: 100%;
	max-width: 720px;
	height: 88vh;
	height: 88dvh;
	max-height: none;
	margin: 0 auto;
	padding: 0;
	border: none;
	border-radius: var(--radius-control) var(--radius-control) 0 0;
	background: var(--surface-0);
	color: var(--color-ink);
	box-shadow: 0 -8px 32px rgb(38 36 37 / 0.16);
	overflow: hidden;
}

.sheet[open] {
	display: flex;
	flex-direction: column;
	animation: sheet-in 400ms cubic-bezier(0.83, 0, 0.17, 1);
}

.sheet::backdrop {
	background: rgb(38 36 37 / 0.32);
}

@keyframes sheet-in {
	from {
		transform: translateY(100%);
	}
}

@media (prefers-reduced-motion: reduce) {
	.sheet[open] {
		animation: none;
	}
}

/* The page behind does not scroll while the sheet is up. */
html.sheet-open {
	overflow: hidden;
}

.sheet-head {
	flex: none;
	display: flex;
	flex-direction: column;
	gap: var(--space-half);
	padding: var(--space-2) var(--space-2) var(--space-1);
	border-bottom: 1px solid var(--color-row-line);
}

/* The sheet's title, 20 caps, as a dialog's title is in the console. */
.sheet-head h2 {
	margin: 0;
	font-size: var(--fs-20);
	font-weight: 400;
	line-height: 1.2;
	text-transform: uppercase;
}

.sheet-body {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	-webkit-overflow-scrolling: touch;
	padding: var(--space-2);
}

.sheet-body:focus {
	outline: none;
}

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

.sheet-body > .error,
.sheet-body > .note {
	margin-bottom: var(--space-half);
}

.sheet-actions {
	flex: none;
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--space-1);
	padding: var(--space-1) var(--space-2) calc(var(--space-1) + env(safe-area-inset-bottom, 0px));
	border-top: 1px solid var(--color-row-line);
}

/* Close alone (the confirmation page has no box to tick). */
.sheet-actions.single {
	grid-template-columns: 1fr;
}

.sheet-actions button {
	width: 100%;
	padding: 0 var(--space-1);
}

/* The idle line while the sheet is up (app.js moves it into the dialog, over
   the dimmed page): at the window's top, clear of the sheet's buttons. */
.sheet .idle {
	top: max(var(--space-1), env(safe-area-inset-top, 0px));
	bottom: auto;
}

/* A phone: the sheet's sides at 16, or the safe area plus 16 on its side. */
@media (max-width: 480px) {
	.sheet-head,
	.sheet-body,
	.sheet-actions {
		padding-left: max(var(--space-1), calc(env(safe-area-inset-left, 0px) + var(--space-1)));
		padding-right: max(var(--space-1), calc(env(safe-area-inset-right, 0px) + var(--space-1)));
	}
}

/* The documents (the sheet and /terms), as the site sets them
   (karmir-web site.css, TERMS): the body in the serif at 20 on 1.5, a
   section's head 20 caps in the sans, a subsection's 20 sans, lists with a
   middle dot; each document under its title, 28 sans on an ink rule (the
   site's 40 is not on this page's scale), 64 apart. */
.legal {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
}

.legal-doc {
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	scroll-margin-top: var(--space-1);
}

.legal-doc h2 {
	margin: 0;
	padding-bottom: var(--space-half);
	border-bottom: 1px solid var(--color-ink);
	font-size: var(--fs-28);
	font-weight: 400;
	line-height: 1.15;
	letter-spacing: -0.01em;
}

.legal-doc h2:focus {
	outline: none;
}

.sheet-body .legal-doc + .legal-doc {
	margin-top: var(--space-4);
}

.legal-body {
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	font-family: var(--font-h02);
	font-size: var(--fs-20);
	line-height: 1.5;
	overflow-wrap: break-word;
}

.legal-body > * {
	margin: 0;
}

.legal-body h3 {
	padding-top: var(--space-1);
	font-family: var(--font-h01);
	font-size: var(--fs-20);
	font-weight: 400;
	line-height: 1.2;
	letter-spacing: -0.01em;
	text-transform: uppercase;
}

.legal-body h4 {
	font-family: var(--font-h01);
	font-size: var(--fs-20);
	font-weight: 400;
	line-height: 1.2;
	letter-spacing: -0.01em;
}

.legal-body ul,
.legal-body ol {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding-left: var(--space-2);
	list-style: none;
}

.legal-body li {
	position: relative;
}

.legal-body li::before {
	content: '·';
	position: absolute;
	left: -20px;
}

.legal-body .draft {
	color: var(--color-gray);
}

/* The read-only page of a version (/terms): the column a reading width, the
   documents' index as a list of links in ink, a row of 44 each. */
.screen.wide {
	max-width: 720px;
}

.legal-index ol {
	margin: 0;
	padding: 0;
	list-style: none;
}

.legal-index li {
	display: flex;
	align-items: center;
	min-height: 44px;
}

.legal-index a {
	color: var(--color-ink);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.15em;
}


.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

@media (max-width: 480px) {
	body {
		--body-top: var(--space-2);
		--body-bottom: calc(var(--space-2) + var(--control-height));
	}
}
