/* One stylesheet, served from this host, referenced by nothing else.
   No web font, no CDN, no analytics: every external reference is a request a censor can
   block and a third party can log, and this page has to render on a network that is
   actively hostile to it. */

/* ONE PALETTE, DARK, IN BOTH THEMES (operator's decision, 2026-09-25).

   There was a light theme and a dark one, and the light one is gone rather than merely
   unused. What settled it was a measurement, not a preference: at the scrim this file
   shipped with — 0.90 light, 0.86 dark — between 10% and 14% of the artwork survived, so
   every question about the picture was moot. Light text tolerates a far thinner scrim
   than dark text does, and a thin scrim is the only condition under which the picture is
   ever seen at all.

   The values are the palette cmd/iconbuild draws the artwork with, and the same ones the
   Android app now uses. The neutrals are WARM — a cool grey ground would tint the scrim,
   and at 0.65 the scrim is no longer a curtain but a veil whose colour is on the picture. */
:root {
	color-scheme: dark;
	--bg: #14100f;
	--fg: #efe7df;
	/* Lighter than the app's muted grey, and the reason is the scrim. The text sits over
	   the picture, so small text has to be legible against the BRIGHTEST thing in it — the
	   sun — not against the page colour. Measured, over #63482E, which is what the sun
	   becomes under a 0.65 scrim:
	       #9e938a  2.80:1   below the 4.5:1 floor for body text
	       #c9bdaf  4.56:1   passes
	   Body text is comfortable either way (6.87:1) and so is the accent (4.55:1); it was
	   only ever the muted text that failed, and it fails in the places a reader needs most
	   — a download's size and hash, the version, the footer. The other lever is a denser
	   scrim, which is the decision this whole palette exists to implement. */
	--muted: #c9bdaf;
	--line: #302825;
	/* The sand of the sun, taken from the artwork. It replaced a mint green: at 65% the
	   sunset shows through, and mint against orange is a complementary pair — it either
	   rings or goes muddy, and never sits quietly. */
	--accent: #f5b168;
	--card: #1e1815;
	/* The note box takes the artwork's warm browns and the sun's track (#A65E37), not the olive
	   it had: against the orange sunset an olive edge read as swamp green (operator, 2026-10-06). */
	--warn-bg: #2d1a10;
	--warn-line: #a65e37;
	/* The header sits over the page and needs to be denser than it, or the nav reads as
	   part of the picture. */
	--header-bg: rgba(20, 16, 15, 0.82);
	/* How much of the page colour sits over the backdrop. THE WHOLE READABILITY QUESTION
	   IS THIS ONE NUMBER: heavier and there is no picture, lighter and there is no text. */
	--scrim: rgba(20, 16, 15, 0.65);
}

* { box-sizing: border-box; }

html { background: var(--bg); }

body {
	margin: 0;
	/* The page colour lives on html, not body: the backdrop is fixed behind body, so a
	   solid body background would cover the picture entirely. */
	background: transparent;
	color: var(--fg);
	font: 16px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* The text column, widened from 44rem by the operator AGAINST the measurement, which is
   recorded rather than argued: a live characters-per-line meter over the shipped font
   reads about 99 characters at 50rem/16px, against a comfortable 45-75. The lever that
   brings that back without narrowing the column is a larger body size. */
.wrap { max-width: 50rem; margin: 0 auto; padding: 0 1.25rem; }

/* The header is STICKY and wider than the text, so the three things in it stay in the
   screen's corners rather than in the column's. Full-bleed was tried and dropped: past
   about 2500px the brand, the nav and the language stop reading as one group. */
header.site {
	position: sticky;
	top: 0;
	z-index: 10;
	background: var(--header-bg);
	backdrop-filter: blur(10px);
	border-bottom: 1px solid var(--line);
}

/* Edge to edge (operator, 2026-10-09): the brand and its tagline against the left edge, the
   language link against the right, a small margin each side. */
header.site .wrap { max-width: none; padding: 0 1rem; }

/* ONE ROW whenever it fits, and the operator's three wishes in order: the tagline on one line,
   the nav over the text column, the header as low as it can be. `minmax(max-content, 1fr)`
   gives each side at least its content and splits what is left equally - so on a wide screen
   the nav is centred on the screen, over the text; on a narrower one the brand keeps its
   width and the nav slides right just enough not to touch it. The earlier `1fr auto 1fr`
   squeezed the tagline to a column a few words wide instead. */
header.site .row {
	display: grid;
	grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr);
	align-items: center;
	gap: 0.5rem 1.5rem;
	padding: 0.8rem 0;
}
header.site .ident { grid-column: 1; }
header.site nav.site { grid-column: 2; }
header.site .lang { grid-column: 3; }

/* TWO ROWS only when one cannot hold the three: the brand and the language link above, the
   nav centred below. Placed, not flowed: auto-placement put the language link AFTER the
   full-width nav, on a third row of its own. */
@media (max-width: 76rem) {
	header.site .row { grid-template-columns: 1fr auto; padding: 0.8rem 0 0.55rem; }
	header.site .ident { grid-row: 1; grid-column: 1; }
	header.site .lang { grid-row: 1; grid-column: 2; }
	header.site nav.site { grid-row: 2; grid-column: 1 / -1; }
}

header.site .ident { min-width: 0; }

.brand { font-size: 1.35rem; font-weight: 650; letter-spacing: -0.01em; color: var(--accent); text-decoration: none; }
.tagline { color: var(--muted); font-size: 0.92rem; margin: 0.1rem 0 0; white-space: nowrap; }

nav.site { justify-self: center; display: flex; gap: 1.1rem; flex-wrap: wrap; font-size: 0.95rem; }
nav.site a { color: var(--muted); text-decoration: none; padding-bottom: 0.2rem; }
nav.site a:hover { color: var(--fg); }
nav.site a.on { color: var(--fg); border-bottom: 2px solid var(--accent); }

.lang { justify-self: end; font-size: 0.88rem; color: var(--muted); text-decoration: none; }
.lang:hover { color: var(--fg); }

main { padding: 2rem 0 3rem; }

/* ONE SIZE FOR EVERY HEADING (operator's decision, stated twice). The page title is
   distinguished by where it sits and by the lede under it, not by being larger. */
h1, h2 { font-size: 1.15rem; font-weight: 650; line-height: 1.25; letter-spacing: -0.01em; }
h1 { margin: 0 0 0.75rem; }
h2 { margin: 2.2rem 0 0.6rem; }
p { margin: 0 0 0.9rem; }
.lede { font-size: 1.06rem; color: var(--fg); }
ul { margin: 0 0 1rem; padding-left: 1.2rem; }
li { margin-bottom: 0.4rem; }
a { color: var(--accent); }
code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 0.92em; background: var(--card); border: 1px solid var(--line); border-radius: 4px; padding: 0.05em 0.35em; }

.note {
	background: var(--warn-bg);
	border: 1px solid var(--warn-line);
	border-left-width: 3px;
	border-radius: 5px;
	padding: 0.75rem 0.9rem;
	margin: 0 0 1.1rem;
	font-size: 0.95rem;
}

.dl { border: 1px solid var(--line); background: var(--card); border-radius: 7px; padding: 1rem 1.1rem; margin-bottom: 1rem; }
.dl h3 { margin: 0 0 0.35rem; font-size: 1rem; }
.dl .meta { color: var(--muted); font-size: 0.85rem; margin: 0.4rem 0 0; }
.dl .hash { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 0.78rem; word-break: break-all; color: var(--muted); }

.plan { border: 1px solid var(--line); background: var(--card); border-radius: 7px; padding: 0.9rem 1.1rem; margin-bottom: 0.8rem; }
.plan .price { font-weight: 650; }

/* The chat. Deliberately plain: it is a text box that costs money per message, not a
   product surface. */
#chat { border: 1px solid var(--line); border-radius: 7px; background: var(--card); padding: 0.9rem; }
#log { min-height: 6rem; max-height: 26rem; overflow-y: auto; }
#log .msg { margin-bottom: 0.8rem; white-space: pre-wrap; overflow-wrap: anywhere; }
#log .who { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); display: block; margin-bottom: 0.15rem; }
/* Lifted from #b4432c, which was picked when the page had a light theme and is too dark
   to read on this ground. */
#log .err { color: #ff8a80; }
form#ask { display: flex; gap: 0.5rem; margin-top: 0.7rem; }
form#ask textarea {
	flex: 1; resize: vertical; min-height: 3.2rem;
	font: inherit; color: var(--fg); background: var(--bg);
	border: 1px solid var(--line); border-radius: 5px; padding: 0.5rem 0.6rem;
}
form#ask button {
	font: inherit; font-weight: 600; cursor: pointer;
	/* NOT white. The accent is a light sand now, and white on it is unreadable; the text
	   takes the darkest brown in the artwork instead of black, which on a fill this bright
	   reads as a hole. */
	background: var(--accent); color: #2a1508; border: 0; border-radius: 5px; padding: 0 1.1rem;
}
form#ask button[disabled] { opacity: 0.55; cursor: default; }

/* The support form. Plain posts with no script, so it looks like the chat but owes it
   nothing: the same field and button styles, written out again for a form the chat's
   selectors do not reach. */
form.ticket { display: flex; flex-direction: column; gap: 0.45rem; margin: 0 0 1.4rem; }
form.ticket label { font-weight: 600; font-size: 0.95rem; }
form.ticket textarea, form.ticket input {
	font: inherit; color: var(--fg); background: var(--bg);
	border: 1px solid var(--line); border-radius: 5px; padding: 0.5rem 0.6rem;
}
form.ticket textarea { resize: vertical; min-height: 6rem; }
form.ticket input { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; letter-spacing: 0.04em; }
form.ticket button {
	align-self: flex-start; font: inherit; font-weight: 600; cursor: pointer;
	background: var(--accent); color: #2a1508; border: 0; border-radius: 5px; padding: 0.5rem 1.2rem;
}
.note.err { border-color: #a5473a; }
/* The new ticket code: the one thing on the page that must be copied before leaving it. */
.code-box { border: 1px solid var(--accent); border-radius: 7px; background: var(--card); padding: 0.9rem 1.1rem; margin: 0 0 1.2rem; }
.code-box .code-label { margin: 0; color: var(--muted); font-size: 0.85rem; }
.code-box .code {
	margin: 0.3rem 0 0.6rem; font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
	font-size: 1.35rem; font-weight: 650; letter-spacing: 0.06em; overflow-wrap: anywhere; user-select: all;
}
.thread { border: 1px solid var(--line); border-radius: 7px; background: var(--card); padding: 0.9rem; margin: 0 0 1rem; }
.thread .msg { margin-bottom: 0.9rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.thread .msg:last-child { margin-bottom: 0; }
.thread .msg.op { border-left: 3px solid var(--accent); padding-left: 0.7rem; }
.thread .who { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); display: block; margin-bottom: 0.15rem; }
.awaiting { color: var(--muted); font-size: 0.9rem; }

/* "This did not help — write to a person", as a button rather than a sentence with a link
   in it. GHOST-styled, because the page already has one filled accent control and it is
   the download: a second one competes with it, and reaching a person is the fallback, not
   the thing we are asking for. */
.contact { margin: 2rem 0 0; }
.contact a {
	display: inline-block;
	color: var(--accent);
	border: 1px solid var(--accent);
	border-radius: 5px;
	padding: 0.45rem 1rem;
	text-decoration: none;
	font-weight: 600;
}
.contact a:hover { background: var(--accent); color: #2a1508; }

footer.site { border-top: 1px solid var(--line); color: var(--muted); font-size: 0.87rem; padding: 1.2rem 0 2.5rem; }
footer.site p { margin: 0 0 0.4rem; }

/* The header's one step down: at 560px the tagline goes, because the brand and the nav are
   what the header is for. */
@media (max-width: 560px) {
	.tagline { display: none; }
}

@media (max-width: 30rem) {
	form#ask { flex-direction: column; }
	form#ask button { padding: 0.6rem; }
}

/* The backdrop: the sunset behind the whole page.

   It is fixed and cropped to cover, so scrolling moves the text over a still picture
   rather than dragging the landscape up the screen. The scrim above it is what keeps the
   text readable: a picture at full strength behind body copy is a picture nobody can read
   over, and the answer is not to make the text heavier but to hold the image back.

   Decorative and aria-hidden: a screen reader gains nothing from a landscape. */
.backdrop {
	position: fixed;
	inset: 0;
	z-index: -2;
	overflow: hidden;
	line-height: 0;
}

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

.backdrop::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--scrim);
}

/* A link from a block of prose to another page of this site (Block.LinkSlug). */
p.more a { font-weight: 600; }

/* "I want this version" on a platform with no app: a ghost button, like the contact one - it
   asks for nothing but a press. */
form.want { margin: 0.6rem 0 0; }
form.want button {
	font: inherit; font-weight: 600; cursor: pointer;
	color: var(--accent); background: transparent;
	border: 1px solid var(--accent); border-radius: 5px; padding: 0.4rem 1rem;
}
form.want button:hover { background: var(--accent); color: #2a1508; }

/* THE PHONE HEADER. Below 560px the brand and the language share the first row, and the nav
   becomes ONE row that scrolls sideways: wrapped, it took three rows of a sticky header - a
   fifth of a phone screen - and every page it gains makes that worse. */
@media (max-width: 560px) {
	header.site .row { grid-template-columns: 1fr auto; row-gap: 0.4rem; padding: 0.6rem 0; }
	header.site .ident { grid-row: 1; grid-column: 1; }
	.lang { grid-row: 1; grid-column: 2; }
	nav.site {
		grid-row: 2; grid-column: 1 / -1; justify-self: stretch;
		flex-wrap: nowrap; overflow-x: auto; white-space: nowrap;
		gap: 1rem; scrollbar-width: none; padding-bottom: 0.15rem;
	}
	nav.site::-webkit-scrollbar { display: none; }
	.brand { font-size: 1.2rem; }
}

/* The shop: a calculator form, the price, and the page that waits for a payment. */
form.calc { display: grid; gap: 0.45rem; max-width: 30rem; margin: 0 0 1rem; }
form.calc label { font-weight: 600; font-size: 0.95rem; }
/* The number field and the select only: a width on every input stretched the term RADIOS to
   8rem each and left them far from their labels. */
form.calc input[type=number], form.calc select {
	font: inherit; color: var(--fg); background: var(--bg);
	border: 1px solid var(--line); border-radius: 5px; padding: 0.45rem 0.6rem; width: 8rem;
}
form.calc .tip { margin: -0.2rem 0 0.4rem; color: var(--muted); font-size: 0.88rem; }
form.calc fieldset { border: 0; padding: 0; margin: 0.4rem 0; display: flex; flex-wrap: wrap; gap: 0.4rem 1.1rem; }
form.calc legend { font-weight: 600; font-size: 0.95rem; padding: 0; margin-bottom: 0.3rem; }
form.calc label.term { font-weight: 400; display: inline-flex; align-items: center; gap: 0.35rem; }
form.calc label.term input { margin: 0; accent-color: var(--accent); }
/* The two sections of the prices page, as links: the state lives in the address, no script. */
nav.tabs { display: flex; flex-wrap: wrap; gap: 0.2rem 1.4rem; border-bottom: 1px solid var(--line); margin: 0 0 1rem; }
nav.tabs a { color: var(--muted); text-decoration: none; padding: 0.3rem 0 0.45rem; margin-bottom: -1px; border-bottom: 2px solid transparent; font-weight: 600; }
nav.tabs a:hover { color: var(--fg); }
nav.tabs a.on { color: var(--fg); border-bottom-color: var(--accent); }
.price .sum { margin: 0.35rem 0 0; font-variant-numeric: tabular-nums; }
/* The price table. It scrolls inside its own box on a phone rather than widening the page. */
.tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: 7px; background: var(--card); margin: 0 0 0.6rem; }
table.prices { border-collapse: collapse; width: 100%; font-size: 0.92rem; font-variant-numeric: tabular-nums; }
table.prices th, table.prices td { padding: 0.45rem 0.6rem; text-align: right; white-space: nowrap; border-bottom: 1px solid var(--line); }
table.prices tbody tr:last-child th, table.prices tbody tr:last-child td { border-bottom: 0; }
table.prices thead th { color: var(--muted); font-weight: 600; font-size: 0.85rem; }
table.prices th:first-child { text-align: left; }
table.prices td span, table.prices th span { display: block; color: var(--muted); font-size: 0.8rem; font-weight: 400; }
table.prices tr.cur th { color: var(--accent); }
table.prices td.cur { color: var(--accent); font-weight: 650; box-shadow: inset 0 0 0 1px var(--accent); }
@media (max-width: 30rem) {
	table.prices { font-size: 0.8rem; }
	table.prices th, table.prices td { padding: 0.4rem 0.3rem; }
	table.prices td span, table.prices th span { font-size: 0.74rem; }
}
form.calc button, .buy button {
	justify-self: start; font: inherit; font-weight: 600; cursor: pointer;
	border-radius: 5px; padding: 0.5rem 1.2rem;
}
/* Recalculate and pay look alike (operator, 2026-10-09): an outline in the accent that fills
   on hover. Pay goes faint and refuses the press while the fields say something other than the
   order priced above - shop.js does that; without the script the server refuses instead. */
form.calc button, .buy button { color: var(--accent); background: transparent; border: 1px solid var(--accent); }
.buy button:disabled { color: var(--muted); border-color: var(--line); opacity: 0.6; cursor: not-allowed; }
.buy .stale { color: var(--muted); font-size: 0.9rem; margin-left: 0.6rem; }
.buy { margin: 1.2rem 0 0.4rem; }
.price { border: 1px solid var(--line); border-radius: 7px; background: var(--card); padding: 0.8rem 1rem; margin: 0 0 0.8rem; }
.price .total { margin: 0; font-size: 1.15rem; }
.price .total strong { font-size: 1.5rem; color: var(--accent); margin-left: 0.4rem; }
.price .meta, p.meta { color: var(--muted); font-size: 0.9rem; margin: 0.3rem 0 0.6rem; }
/* The line over the calculator: the base price and how far discounts go. */
p.headline { font-size: 1.06rem; font-weight: 600; margin: 0 0 1.1rem; }
.status { font-weight: 600; }
.status.ok { color: #9fd7a0; }
.pay { border: 1px solid var(--accent); border-radius: 7px; background: var(--card); padding: 0.9rem 1rem; margin: 0.6rem 0 1rem; }
.pay .field { display: grid; gap: 0.15rem; margin: 0 0 0.6rem; }
.pay .field span { color: var(--muted); font-size: 0.85rem; }
code.sel { user-select: all; font-size: 1rem; padding: 0.2rem 0.4rem; }
code.addr { overflow-wrap: anywhere; font-size: 0.85rem; line-height: 1.5; }
/* Dark on white, whatever the theme: that is what wallet scanners expect. */
a.qrwrap { display: inline-block; background: #fff; padding: 0.4rem; border-radius: 6px; margin: 0.2rem 0 0.4rem; }
svg.qr { display: block; width: 13rem; height: 13rem; }
ul.codes { list-style: none; padding: 0; }
ul.codes li { margin: 0 0 0.4rem; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
ul.codes code { font-size: 1.1rem; user-select: all; padding: 0.25rem 0.5rem; }
/* The copy buttons: the usual two-sheets icon, a tick for a moment once copied. Hidden until
   copy.js shows them - the [hidden] rule matters, since display below would override it. */
button.copy {
	display: inline-flex; align-items: center; gap: 0.4rem; cursor: pointer; font: inherit;
	color: var(--accent); background: transparent; border: 1px solid var(--line); border-radius: 5px; padding: 0.3rem 0.4rem;
}
button.copy[hidden] { display: none; }
button.copy.all { padding: 0.4rem 0.8rem; font-weight: 600; }
button.copy svg { width: 1.1rem; height: 1.1rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
button.copy .i-done, button.copy.done .i-copy { display: none; }
button.copy.done .i-done { display: inline; }

/* EVERY control answers the pointer and the keyboard (operator, 2026-10-09). Outlined buttons
   fill with the accent on hover, as the contact and "I want this version" buttons already did;
   filled ones lighten; anything reached by the keyboard gets a visible ring. */
form.calc button:hover, .buy button:hover:not(:disabled), button.copy:hover {
	background: var(--accent); color: #2a1508; border-color: var(--accent);
}
form#ask button:hover:not([disabled]), form.ticket button:hover { filter: brightness(1.12); }
button, .contact a { transition: background-color 0.12s, color 0.12s, border-color 0.12s, filter 0.12s; }
button:active:not(:disabled) { transform: translateY(1px); }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
	outline: 2px solid var(--accent); outline-offset: 2px;
}

/* Screenshots of the apps (the Guide). Phone shots are tall, so they sit two to a row -
   about their own width on a desktop - and each opens full size, which is what a phone needs. */
.shots { display: flex; flex-wrap: wrap; gap: 1rem; margin: 0.4rem 0 1.4rem; }
.shots figure { margin: 0; flex: 0 1 calc(50% - 0.5rem); }
.shots img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: 10px; }
.shots figcaption { color: var(--muted); font-size: 0.85rem; margin-top: 0.35rem; }
@media (max-width: 30rem) {
	.shots { gap: 0.6rem; }
	.shots figure { flex-basis: calc(50% - 0.3rem); }
}
.shots a { display: block; }
.shots figure.wide { flex-basis: 100%; max-width: 46rem; }
.shots figure.wide img { border: 0; border-radius: 6px; }
