:root {
  color-scheme: light;
  --sand-50: #faf7f2;
  --sand-600: #6b6255;
  --sand-500: #8a8071;
  --ink: #26231e;
  --surface: #ffffff;
  --border: #ece5da;
  --border-strong: #d5ccbc;
  --shadow-sm: 0 1px 2px rgb(38 35 30 / 5%), 0 2px 6px rgb(38 35 30 / 5%);
  --accent: #dc4a1d;
  --accent-hover: #c13e14;
  --accent-soft: #ffede3;
  --focus-ring: 0 0 0 3px rgb(220 74 29 / 24%);
  --stage-idea: #f2a413;
  --stage-design: #d8447e;
  --stage-plan: #3d66d8;
  --stage-build: #dc4a1d;
  --stage-live: #14a79b;
  --measure: 34rem;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  padding: 0 1.25rem 3rem;
  background: var(--sand-50);
  color: var(--ink);
  font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 1.0625rem;
  line-height: 1.6;
}

.wrap { max-width: var(--measure); margin: 0 auto; }

a { color: var(--accent); }
a:hover { color: var(--accent-hover); }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

.top { padding: 2rem 0 1.25rem; }

.tl-wordmark {
  font-size: 1.5rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.tl-wm-idea { color: var(--stage-idea); }
.tl-wm-design { color: var(--stage-design); }
.tl-wm-plan { color: var(--stage-plan); }
.tl-wm-build { color: var(--stage-build); }
.tl-wm-live { color: var(--stage-live); }

main {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--shadow-sm);
  padding: 1.75rem 1.5rem;
}

h1 {
  font-size: 1.625rem;
  line-height: 1.25;
  letter-spacing: -0.02em;
  font-weight: 680;
  margin: 0 0 1rem;
}
h2 { font-size: 1.0625rem; font-weight: 650; margin: 1.75rem 0 0.5rem; }
p { margin: 0 0 1rem; }

section { margin: 0 0 1.25rem; }
section p:last-child { margin-bottom: 0; }

ul { margin: 0 0 1.25rem; padding-left: 1.25rem; }
li { margin-bottom: 0.25rem; }

.lead { font-size: 1.1875rem; margin-bottom: 1.25rem; }
.muted { color: var(--sand-600); }

label { display: block; margin: 0 0 1.125rem; font-size: 0.9375rem; font-weight: 600; }

input[type="email"],
input[type="password"],
input[type="text"],
input:not([type]),
select {
  display: block;
  width: 100%;
  min-height: 2.875rem;
  margin-top: 0.4375rem;
  padding: 0.6875rem 0.8125rem;
  font: inherit;
  font-weight: 400;
  color: var(--ink);
  background-color: var(--sand-50);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  transition: border-color 120ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 120ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

input[type="email"]:hover:not(:focus),
input[type="password"]:hover:not(:focus),
input[type="text"]:hover:not(:focus),
input:not([type]):hover:not(:focus),
select:hover:not(:focus) { border-color: var(--sand-500); }
/*
 * A field owns its own focus look, and takes itself out of the blanket rule
 * above (2026-08-21).
 *
 * The blanket rule is right for a link and for a button, which have no other way
 * to say they are the thing the keyboard is pointing at. A FIELD already has
 * one: it turns its edge accent and its fill white. Leaving the blanket rule to
 * fire as well drew a second, detached ring three pixels outside the first, so
 * one box wore two outlines - which is the same defect the desktop shell was
 * carrying on its typing boxes, found on the same day.
 *
 * What replaces the outline is the ring the desktop app uses, so signing in and
 * using the product feel like one piece of software. It is a soft fill rather
 * than a hard line, and the accent edge underneath it is what carries the
 * contrast - the two are one indicator and neither is decoration.
 */
input[type="email"]:focus,
input[type="password"]:focus,
input[type="text"]:focus,
input:not([type]):focus,
select:focus {
  border-color: var(--accent);
  background-color: var(--surface);
  box-shadow: var(--focus-ring);
}
input[type="email"]:focus-visible,
input[type="password"]:focus-visible,
input[type="text"]:focus-visible,
input:not([type]):focus-visible,
select:focus-visible { outline: none; }

/*
 * The country list draws its own arrow, out of two gradients rather than a
 * picture. No rule in this file may fetch anything, and a select left at its
 * native appearance is the one control on these pages that would wear the
 * operating system's shape instead of the product's. The gradients are two
 * triangles that meet, which is a chevron, and they cost no request.
 *
 * Note what the two rules above deliberately do **not** say: neither the shared
 * fill nor the focus fill is written as the background shorthand any more. They
 * were, and the focus one outspecifies this rule - so the arrow vanished the
 * moment somebody put the cursor in the field, which is the one moment it is
 * being looked at. A shorthand resets every background property it does not
 * mention, the background image included. Set the colour, never the shorthand,
 * on anything this rule draws on. Note also that this comment lives inside the
 * one template literal, so it may not quote a property name the way the rest of
 * this repository would - a backtick here would end the stylesheet.
 */
select {
  -webkit-appearance: none;
  appearance: none;
  padding-right: 2.5rem;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--sand-600) 50%),
    linear-gradient(135deg, var(--sand-600) 50%, transparent 50%);
  background-position:
    calc(100% - 1.1875rem) calc(50% + 0.0625rem),
    calc(100% - 0.8125rem) calc(50% + 0.0625rem);
  background-size: 0.375rem 0.375rem;
  background-repeat: no-repeat;
}

input[type="checkbox"] { margin-right: 0.5rem; accent-color: var(--accent); }

/*
 * What a field means, under the field rather than in its name: how long a
 * password has to be, what an address is used for, why a declaration is asked
 * for at all. A person who reads it before typing never meets the refusal it
 * describes - which is the whole reason it is here and not in a message shown
 * after a failed attempt.
 */
.hint {
  display: block;
  margin: 0.4375rem 0 0;
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--sand-600);
}

/*
 * A group of choices, with no box drawn around it. The element is the right
 * element - it is a set of options with one question over them - and its default
 * frame is the wrong picture, because a bordered box inside a bordered card
 * reads as a second card rather than as one question.
 */
fieldset { border: 0; padding: 0; margin: 0 0 1.25rem; }
legend { padding: 0; font-size: 0.9375rem; font-weight: 600; }

button {
  display: inline-block;
  padding: 0.6875rem 1.375rem;
  font: inherit;
  font-weight: 620;
  color: #ffffff;
  background: var(--accent);
  border: 0;
  border-radius: 10px;
  cursor: pointer;
}
button:hover { background: var(--accent-hover); }

/*
 * The one act a page exists for, as wide as the column it finishes. A small
 * button at the foot of a long form reads as one more control among the
 * checkboxes above it; this one cannot be mistaken for anything else, and it
 * lines up with the ways in offered at the top of the same page.
 */
button.wide { display: block; width: 100%; padding: 0.8125rem 1.375rem; }

button.quiet {
  color: var(--accent);
  background: var(--surface);
  border: 1px solid var(--border);
  font-weight: 560;
}
button.quiet:hover { background: var(--accent-soft); border-color: var(--accent); }

.call {
  display: inline-block;
  padding: 0.6875rem 1.375rem;
  font-weight: 620;
  color: #ffffff;
  background: var(--accent);
  border-radius: 10px;
  text-decoration: none;
}
.call:hover { color: #ffffff; background: var(--accent-hover); }

form { margin: 0 0 1.25rem; }
form:last-child { margin-bottom: 0; }

/*
 * A sentence the page is announcing rather than a sentence it is telling: what
 * just happened, or why the person is being asked again. The refused one wears
 * the accent, which is the only strong colour on the page.
 */
.notice {
  background: var(--sand-50);
  border: 1px solid var(--border);
  border-left: 4px solid var(--sand-600);
  border-radius: 0 10px 10px 0;
  padding: 0.875rem 1.125rem;
  margin: 0 0 1.25rem;
  font-weight: 560;
}
.notice.good { border-left-color: var(--stage-live); }
.notice.refused {
  background: var(--accent-soft);
  border-color: var(--accent);
  border-left-color: var(--accent);
}

/* What a person is agreeing to, framed apart from the fields they fill in. */
.note {
  background: var(--sand-50);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.9375rem 1.0625rem;
  margin: 0 0 0.625rem;
}
.note h2 { margin: 0 0 0.25rem; font-size: 1rem; }
.note p { margin: 0 0 0.5rem; font-size: 0.9375rem; }
.note p:last-child { margin-bottom: 0; }

/*
 * Everything a person is agreeing to, in one region with one heading over it.
 *
 * These sentences used to sit between the title and the first field, so the page
 * opened with two paragraphs of terms and the thing a person came to do began
 * below the fold. They are the same sentences under the same conspicuous
 * headings - they have simply moved to where the agreeing happens, directly
 * above the boxes that say "I have read and accept" and the button that acts on
 * them. Nothing here is smaller, quieter or later than it was: it is one screen
 * nearer the tick.
 */
.agree { margin: 1.75rem 0 1.25rem; }
.agree > h2 { margin: 0 0 0.625rem; }

.packet {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  list-style: none;
  padding: 0;
  margin: 0 0 0.875rem;
  font-size: 0.9375rem;
}
.packet li { margin: 0; }

/*
 * The two capacities, as one visibly chosen option beside its alternative.
 *
 * The chosen one is **filled**, not tinted. Tinted, the pair read as two
 * unpressed buttons with one hovered, which is exactly how the pair looked to
 * the founder: a question the page had not answered. Filled, there is one
 * obvious answer showing and one obvious way to change it, which is what the
 * page has always meant - a capacity is declared for every account, and the
 * link beside it is how a person says the other thing is true.
 *
 * Filled with the ink rather than the accent, and that is the whole reason this
 * rule is longer than a line. The accent is the page's one loud colour and it
 * belongs to the act at the foot of the form; an accent-filled pill in the
 * middle of the same column is a second thing shouting, and a person scanning
 * for what to press finds two. Ink says chosen without asking to be pressed.
 */
.choices { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.625rem 0 0; }
.choice {
  display: inline-block;
  padding: 0.5625rem 1rem;
  font-size: 0.9375rem;
  font-weight: 560;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  text-decoration: none;
}
.choice:hover { color: var(--accent-hover); background: var(--accent-soft); border-color: var(--accent); }
.choice.current {
  color: var(--surface);
  background: var(--ink);
  border-color: var(--ink);
  font-weight: 620;
}
.choice.current:hover {
  color: var(--surface);
  background: var(--ink);
  border-color: var(--ink);
}

/*
 * The ways in that are not a password, as a column of equal-weight controls.
 *
 * A column rather than a row: the names are different lengths, and a row of
 * unequal buttons reads as different kinds of thing.
 *
 * **One look for both pages, whether the control is a button or a link.** On the
 * sign-in page each is a button that posts; on the sign-up page each is a link,
 * because taking one lands on the same page in its provider shape and every way
 * in has to ask for its own acceptance. That is a real difference in what
 * happens and no difference at all in what a person is choosing, so the two wear
 * one class - which is also what stopped the sign-up page offering them as the
 * small pill it uses for a capacity, three screens below the form.
 *
 * A backtick cannot appear anywhere in this file: the stylesheet is one template
 * literal, so one would end it.
 */
.providers { display: flex; flex-direction: column; gap: 0.625rem; }
.provider {
  display: block;
  width: 100%;
  padding: 0.8125rem 1rem;
  font: inherit;
  font-size: 1rem;
  font-weight: 620;
  text-align: center;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  text-decoration: none;
  cursor: pointer;
}
.provider:hover {
  color: var(--accent-hover);
  background: var(--accent-soft);
  border-color: var(--accent);
}

/*
 * The word between the two ways in. A rule either side of it, so it reads as a
 * fork in the page rather than as a sentence about the buttons above it.
 */
.split {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  margin: 1.5rem 0;
  color: var(--sand-500);
  font-size: 0.875rem;
}
.split::before,
.split::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--border);
}

/*
 * A box and its sentence on one line, so the sentence never hangs under it - and
 * the declarations as one set with one gap, rather than three full-width cards
 * stacked a whole line apart looking like three separate demands.
 */
.checks { display: flex; flex-direction: column; gap: 0.5rem; margin: 0 0 1.5rem; }
.check {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  margin: 0;
  padding: 0.75rem 0.875rem;
  font-size: 0.9375rem;
  font-weight: 400;
  background: var(--sand-50);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
}
.check:hover { border-color: var(--border-strong); }
.check input[type="checkbox"] {
  flex: none;
  width: 1.0625rem;
  height: 1.0625rem;
  margin: 0.1875rem 0 0;
}

/* The second way in, kept visibly second. */
.alt { border-top: 1px solid var(--border); margin-top: 1.5rem; padding-top: 1.5rem; }
.alt h2 { margin-top: 0; }
/*
 * One rule, not two. The sign-in page puts the way back in for a forgotten
 * password directly above the ways in that are not a password, and each drew its
 * own line - so a short page carried two rules a centimetre apart with a single
 * link between them. They are one region: other ways in.
 */
.door + .alt { border-top: 0; margin-top: 1.125rem; padding-top: 0; }

/*
 * Who is signed in: values a person reads rather than fills in, so they are not
 * dressed as fields. An address can be long and unbreakable, and a page that
 * scrolls sideways on a phone because of one is a page nobody can read - hence
 * the wrap.
 */
.identity { margin: 0 0 1.5rem; }
.identity dt { color: var(--sand-600); font-size: 0.9375rem; }
.identity dd { margin: 0.125rem 0 1rem; font-weight: 560; overflow-wrap: anywhere; }
.identity dd:last-child { margin-bottom: 0; }

/* A state beside a value rather than a sentence under it. */
.tag {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.0625rem 0.5rem;
  font-size: 0.875rem;
  font-weight: 560;
  color: var(--sand-600);
  background: var(--sand-50);
  border: 1px solid var(--border);
  border-radius: 999px;
}
.tag.good { color: var(--stage-live); border-color: var(--stage-live); }
.tag.waiting {
  color: var(--accent-hover);
  background: var(--accent-soft);
  border-color: var(--accent);
}

/*
 * The pages this one leads to. Each is a whole place to go, so each is a line of
 * its own with the sentence that says what is there - a row of links would make
 * a person guess which one holds the thing they came for.
 */
.doors { margin: 0 0 1.5rem; padding: 0; list-style: none; border-top: 1px solid var(--border); }
.doors li { margin: 0; padding: 0.875rem 0.25rem; border-bottom: 1px solid var(--border); }
.doors a { font-weight: 620; text-decoration: none; }
.doors a:hover { text-decoration: underline; }
.doors p { margin: 0.125rem 0 0; font-size: 0.9375rem; }

/*
 * Where this account is signed in. One computer per line, each with the two
 * times that let a person recognise it and the one control that ends it - the
 * control quiet rather than loud, because ending a sign-in is a decision a
 * person makes about one line rather than the page's main action.
 */
.devices {
  margin: 0 0 1.25rem;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--border);
}
.devices li { margin: 0; padding: 1rem 0.25rem; border-bottom: 1px solid var(--border); }
.devices h3 { margin: 0 0 0.5rem; font-size: 1.0625rem; font-weight: 650; }
.devices form { margin: 0.75rem 0 0; }
.devices button { padding: 0.5rem 1rem; font-size: 0.9375rem; }

/*
 * When a sign-in began and when it was last used, side by side where there is
 * room and stacked where there is not. Read rather than filled in, so the two
 * are labelled the way the identity block labels an address.
 */
.when { display: flex; flex-wrap: wrap; gap: 0.5rem 2rem; margin: 0; font-size: 0.9375rem; }
.when dt { color: var(--sand-600); }
.when dd { margin: 0; font-weight: 560; }

/*
 * Something shown exactly once: a setup key, a setup address, a set of recovery
 * codes. Framed apart from everything else on the page, because the whole page
 * is asking a person to stop and copy what is inside these before they leave.
 */
.once {
  background: var(--sand-50);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1rem 1.125rem;
  margin: 0 0 1.25rem;
}
.once h2 { margin: 0 0 0.375rem; }
.once p { margin: 0 0 0.625rem; }

/*
 * A value to be copied rather than read: a fixed pitch so a person can tell an
 * l from a 1, wrapping anywhere because a setup address has no spaces in it and
 * a page that scrolls sideways is a page nobody can copy from, and selectable in
 * one click since these pages carry no script to put anything on a clipboard.
 */
.value {
  display: block;
  padding: 0.625rem 0.75rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9375rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 9px;
  overflow-wrap: anywhere;
  user-select: all;
}

/* The recovery codes, as a set a person can read down rather than a paragraph. */
.codes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: 0.5rem;
  list-style: none;
  padding: 0;
  margin: 0;
}
.codes li {
  margin: 0;
  padding: 0.4375rem 0.625rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9375rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 9px;
  user-select: all;
}

/* The door to the other page a person may have wanted. */
.door {
  border-top: 1px solid var(--border);
  margin: 1.5rem 0 0;
  padding-top: 1.25rem;
  color: var(--sand-600);
  font-size: 0.9375rem;
}

.foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin-top: 1.5rem;
  padding: 0 0.25rem;
  color: var(--sand-600);
  font-size: 0.9375rem;
}

@media (min-width: 40rem) {
  body { padding: 0 2rem 4rem; }
  main { padding: 2.25rem 2rem; }
  h1 { font-size: 1.875rem; }
}
