/* Shared stylesheet for the public pages under onebonus.app — the hand-written
   ones (account/deletion, 404) and the two generated from the app's legal
   documents (scripts/build-site.mjs).
 *
 * Separate from the landing, which stays a single self-contained file: these are
 * several documents that must look like each other, and the alternative is the
 * same 120 lines pasted into every one of them.
 *
 * ── Where the design comes from ───────────────────────────────────────────────
 *
 * These pages are dressed as the app, not as the marketing landing: the tokens,
 * the type ramp, the card surfaces and the glyph rows below are the ones the
 * in-app account-deletion sheet uses (src/pages/account/blocks/accountDelete).
 *
 * That is a deliberate switch away from mirroring the landing's palette. The
 * deletion page runs the app's own four-call flow against the app's own API, and
 * a visitor who lands on it from a store listing is being asked to act on their
 * account — the screen should look like the account it is about to close, not
 * like an advertisement. The privacy policy and the terms are the same text the
 * app renders in its own sheet, so they follow.
 *
 * Continuity with the landing is carried by the two things a reader actually
 * recognises: the brand mark in the header, and the violet.
 *
 * The values are the app's, resolved one step: what the app writes as
 * `--mantine-color-gray-1` or `light-dark(red-0, dark-6)` is written here as the
 * hex it resolves to, since there is no Mantine on these pages. Names match
 * `src/styles/global.css` (`--ink`, `--fill`, `--card`, …) so the two files can
 * be read side by side. Keep them in step. */
:root {
  color-scheme: light;

  /* Text — ink is dark.8, soft is gray.8 (the app's `dimmed`, not gray.6 which
     is the placeholder grey), faint is gray.6. */
  --ink: #101216;
  --ink-soft: #5e6c84;
  --faint: #8996a8;

  /* Surfaces. The ground is plain white, as in the app: the content column and
     the fixed header read as one sheet, and a card is separated by its ring
     rather than by a grey wash behind it. */
  --ground: #fff;
  --card: #fff;
  --fill: #f3f4f7; /* gray.1 — the flat box behind a hint or a field */
  --hair: #f3f4f7; /* row separator inside a card */
  --ring: #e9ecf0; /* gray.2 — the card's own hairline */
  --line: #e2e8f0; /* gray.3 — field and ghost-button border */

  /* Brand. violet.6 is both the fill and, in light, the readable foreground. */
  --brand: #7c25ff;
  --brand-fg: #7c25ff;
  --brand-wash: #f4edff; /* violet.0 — a selected row, the way back */
  --brand-ink: #4d00a8; /* violet.8 — a title on that wash */
  --brand-ink-soft: #6500d8; /* violet.7 */

  /* Destructive. The wash carries the consent; the strong shade carries the
     numbers and the label on it. */
  --red: #e5484d; /* red.6 */
  --red-strong: #c32633; /* red.7 */
  --red-wash: #fde7e6; /* red.0 */
  --red-ring: #ffd9d6; /* red.1 */

  --shadow-card: inset 0 0 0 1px var(--ring), 0 4px 12px rgb(29 36 43 / 5%);
  --shadow-brand: inset 0 1px 2px rgb(255 255 255 / 25%), 0 6px 18px rgb(124 37 255 / 28%);

  /* The brand gradient, four stops, top-left to bottom-right — the app's
     `--ob-gradient-brand`, carried by every primary button. */
  --gradient-brand: linear-gradient(
    135deg,
    #1d85f8 14.64%,
    #4a4bff 35.86%,
    #7c25ff 57.07%,
    #c218ff 85.36%
  );

  /* The app's radius scale — the two rungs these pages use: cards and the
     sheet at `lg`, fields at `md`. */
  --r-md: 16px;
  --r-lg: 20px;

  /* Onest, as in the app — from Google Fonts here rather than the bundled
     variable file, since these pages ship no assets of their own. */
  --font: Onest, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

/* The app inverts through `[data-mantine-color-scheme]`, which it writes from a
   stored preference; these pages do the same through `[data-theme]`, which
   /theme.js writes before the first paint — from the visitor's stored choice,
   or from the system when they have not made one. The switch in the header is
   what stores it, and the landing page shares the key, so a theme picked on
   either side of the site holds on the other.

   Keyed on the attribute alone rather than also on a `prefers-color-scheme`
   query: two sources for one palette means writing it twice, and the one thing
   that buys — dark for a visitor with JS off — is not worth a second copy to
   keep in step. */
:root[data-theme='dark'] {
  color-scheme: dark;

  --ink: #f8f9fb; /* gray.0 */
  --ink-soft: #99a3b3; /* dark.2 — the app's dimmed in dark */
  --faint: #6e798b; /* dark.3 */

  --ground: #16181d; /* dark.7 */
  --card: #22262e; /* dark.6 */
  --fill: #333a46; /* dark.5 */
  --hair: #333a46;
  --ring: rgb(255 255 255 / 7%);
  --line: #454e5e; /* dark.4 */

  /* Up the ramp, not down: on a dark surface the readable brand tone is a
     light violet, and the wash is a whisper of it over the card. */
  --brand-fg: #b2a0ff; /* violet.3 */
  --brand-wash: #322a4a; /* violet.6 at 16% over dark.6 */
  --brand-ink: #dfd9ff; /* violet.1 */
  --brand-ink-soft: #c8bdff; /* violet.2 */

  --red: #f66161; /* red.5 */
  --red-strong: #ff7f7c; /* red.4 — the value colour in dark */
  --red-wash: #22262e; /* the card itself; the ring does the work */
  --red-ring: #9f001d; /* red.8 */

  --shadow-card: inset 0 0 0 1px var(--ring), 0 8px 24px rgb(0 0 0 / 45%);
}

* {
  box-sizing: border-box;
}

/* The `hidden` attribute is how the sheet's script shows one step, one footer
   and one error at a time — and the UA rule behind it is a plain `display:
   none` that any author `display` outranks, whatever the specificity. Several
   rules below set one (`.ic`, `.error`, the step and footer columns), so
   without this an empty flex box keeps its gap and a hidden glyph keeps
   painting. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px; /* the app's body rung */
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.wrap {
  max-width: 780px;
  margin: 0 auto;
  padding: 0 20px;
}

/* ─────────────────────────────  frame  ───────────────────────────────────── */

header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid var(--ring);
}

.bar {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 64px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--ink);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.01em;
}

.brand img {
  display: block;
  width: 26px;
  height: 26px;
}

/* Language switch. Three of them rather than a menu: the whole set is nine
   characters wide, and a menu would hide the one fact the row states, which is
   that the page exists in the reader's language at all.

   Links on the generated documents, where a language is a URL, and buttons on
   the pages that translate themselves in place — see lang.js. The two are one
   control to look at, so they are one rule here. */
.langs {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--card);
}

.langs a,
.langs button,
.langs .on {
  display: inline-grid;
  place-items: center;
  min-width: 30px;
  height: 26px;
  padding: 0 6px;
  border-radius: calc(var(--r-md) - 3px);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  color: var(--ink-soft);
  transition:
    color 0.15s ease,
    background 0.15s ease;
}

.langs button {
  border: 0;
  font-family: inherit;
  cursor: pointer;
  background: transparent;
}

.langs a:hover,
.langs button:hover {
  color: var(--brand-fg);
  background: var(--fill);
}

/* The language showing is not a way to it: on the documents it is a plain
   <span> where the others are links, and on the rest a button that is already
   pressed. Either way it is the one that reads as on. */
.langs .on,
.langs a[aria-current='true'],
.langs button[aria-current='true'] {
  color: var(--brand-ink-soft);
  background: var(--brand-wash);
}

/* `.theme` claims the free space on the pages that have no switch; where the
   switch is present it has already claimed it, and the two sit together. */
.langs + .theme {
  margin-left: 6px;
}

/* Theme switch, at the far end of the header bar. A quiet square: it is a
   preference, not an action the page is asking for. */
.theme {
  display: inline-grid;
  place-items: center;
  margin-left: auto;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--card);
  color: var(--ink-soft);
  cursor: pointer;
  transition:
    color 0.15s ease,
    border-color 0.15s ease;
}

.theme:hover {
  color: var(--brand-fg);
  border-color: var(--brand-fg);
}

.theme .ic {
  width: 18px;
  height: 18px;
}

/* One glyph at a time, and it names the destination rather than the current
   state: the moon offers the dark theme, the sun offers the way back — the same
   thing the button's label says. */
.theme .ic-sun {
  display: none;
}

:root[data-theme='dark'] .theme .ic-sun {
  display: block;
}

:root[data-theme='dark'] .theme .ic-moon {
  display: none;
}

/* `main` and `footer` both carry `.wrap` for the column, and a class beats a
   type selector whatever the order — so vertical padding written as `main { }`
   is silently dropped by `.wrap`'s shorthand and the document card ends up
   touching the header. Hence the qualified selectors and the longhands. */
main.wrap {
  padding-top: 32px;
  padding-bottom: 64px;
}

/* The document itself, as a card: the app's `Paper radius="lg"` with the
   `shadow-sm` ring — one surface a step in front of the page. */
article {
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  padding: 32px clamp(20px, 5vw, 40px) 36px;
}

footer {
  border-top: 1px solid var(--ring);
  color: var(--faint);
  font-size: 13px;
  line-height: 1.5;
}

footer.wrap {
  padding-top: 24px;
  padding-bottom: 40px;
}

footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-bottom: 12px;
}

footer nav a {
  color: var(--ink-soft);
  text-decoration: none;
}

footer nav a:hover {
  color: var(--brand-fg);
}

/* ──────────────────────────  document type  ──────────────────────────────── */

h1 {
  font-weight: 700;
  font-size: clamp(25px, 5vw, 28px);
  line-height: 1.25;
  letter-spacing: -0.025em;
  margin: 0 0 10px;
  text-wrap: pretty;
}

/* Revision / owner line. A pill rather than a grey sentence: the app states this
   kind of meta as a tinted badge, and it keeps the line from reading as the
   document's first paragraph. */
.meta {
  display: inline-block;
  margin: 0 0 24px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--fill);
  color: var(--ink-soft);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
}

/* The preamble, in the app's `.infoBox`: a flat fill box with a glyph, which is
   how the sheet introduces anything the reader should take in before acting. */
.lead {
  display: flex;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--r-lg);
  background: var(--fill);
  margin: 0 0 28px;
}

.lead .ic {
  flex: none;
  width: 22px;
  height: 22px;
  margin-top: 2px;
  color: var(--faint);
}

.lead div {
  min-width: 0;
}

.lead p {
  color: var(--ink-soft);
  font-size: 15px;
  line-height: 1.55;
  margin: 0;
  text-wrap: pretty;
}

.lead p + p {
  margin-top: 10px;
}

/* Section heading, with the section number in a tinted square — the app's glyph
   tile, standing in for an icon the document does not have. */
h2 {
  display: flex;
  align-items: center;
  gap: 12px;
  font-weight: 700;
  font-size: 20px;
  line-height: 1.35;
  letter-spacing: -0.015em;
  margin: 32px 0 12px;
  padding-top: 26px;
  border-top: 1px solid var(--hair);
  scroll-margin-top: 84px;
  text-wrap: pretty;
}

h2:first-of-type {
  border-top: 0;
  padding-top: 0;
  margin-top: 24px;
}

h2 .badge {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 10px;
  background: var(--brand-wash);
  color: var(--brand-ink-soft);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}

p,
li {
  color: var(--ink-soft);
  text-wrap: pretty;
}

.clause {
  margin: 0 0 10px;
}

/* Sub-items carry the clause number, so they need indent, not bullets. A rung
   down from the clause they belong to, as helper text is in the app. */
.items {
  list-style: none;
  margin: 8px 0 12px;
  padding: 0 0 0 18px;
}

.items li {
  font-size: 15px;
  line-height: 1.55;
  margin: 0 0 6px;
}

.num {
  color: var(--ink);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

a {
  color: var(--brand-fg);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* ────────────────────────  contents (long documents)  ────────────────────── */

/* The same card-of-rows the sheet lists an account's contents in: a numbered
   tile, a label, a chevron. Two documents of ~170 numbered clauses each are
   unreadable without a way in. */
.toc {
  margin: 0 0 8px;
  border-radius: var(--r-lg);
  background: var(--fill);
  overflow: hidden;
}

.toc a {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 16px;
  color: var(--ink);
  font-size: 15px;
  text-decoration: none;
}

.toc a:not(:last-child) {
  box-shadow: inset 0 -1px 0 var(--ring);
}

.toc a:hover {
  color: var(--brand-fg);
}

.toc .n {
  flex: none;
  width: 22px;
  color: var(--faint);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.toc .t {
  flex: 1;
  min-width: 0;
}

.toc .ic {
  flex: none;
  width: 16px;
  height: 16px;
  color: var(--faint);
}

/* ────────────────────────────  glyph rows  ───────────────────────────────── */

/* A list of the account's own things — what is deleted, what it holds. The
   app's inventory card: an ordinary surface, with the red carried by the glyphs
   and the values rather than by a wash under the whole list. */
.rows {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  border-radius: var(--r-lg);
  background: var(--card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.rows li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  color: var(--ink);
  font-size: 15px;
  line-height: 1.45;
}

.rows li:not(:last-child) {
  box-shadow: inset 0 -1px 0 var(--hair);
}

/* The shared 24px glyph slot. */
.rows .ic {
  flex: none;
  width: 22px;
  height: 22px;
  color: var(--red);
}

.rows .label {
  flex: 1;
  min-width: 0;
}

.rows b {
  flex: none;
  color: var(--red-strong);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ───────────────────────────  tinted boxes  ──────────────────────────────── */

/* Flat fill, dimmed glyph: a fact the reader should have before the next step.
   The grace period is the one this exists for. */
.note {
  display: flex;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--r-lg);
  background: var(--fill);
  margin: 0 0 12px;
  color: var(--ink-soft);
  font-size: 15px;
  line-height: 1.55;
}

.note > .ic {
  flex: none;
  width: 22px;
  height: 22px;
  margin-top: 1px;
  color: var(--faint);
}

.note div {
  min-width: 0;
}

.note b,
.note strong {
  color: var(--ink);
  font-weight: 600;
}

/* The one violet surface on a screen otherwise made of greys and reds — the way
   back, which should be the only thing that looks like an offer. */
.restore {
  display: flex;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--r-lg);
  background: var(--brand-wash);
  margin: 0 0 12px;
}

.restore > .ic {
  flex: none;
  width: 22px;
  height: 22px;
  margin-top: 2px;
  color: var(--brand-fg);
}

.restore div {
  min-width: 0;
}

.restore .title {
  color: var(--brand-ink);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.45;
}

.restore p {
  color: var(--brand-ink-soft);
  font-size: 15px;
  line-height: 1.5;
  margin: 4px 0 0;
}

/* ─────────────────────────────  the sheet  ────────────────────────────────
   Only the account-deletion page uses these: it is the one public page that
   does something rather than saying something — and what it does is the app's
   own bottom sheet (src/pages/account/blocks/accountDelete), so it is built as
   one rather than as a document with a form in it.

   Same three parts as `CModal`: a title bar carrying the step's title, a body,
   and a footer with the step's buttons. Capped at the app's own column width,
   like the sheet is. Kept here rather than inlined there so the sheet inherits
   the same tokens as the pages around it. */
.sheet {
  --sheet-pad: clamp(16px, 4vw, 24px);

  max-width: 600px; /* --ob-app-width, the width the sheet has in the app */
  margin: 0 auto;
  background: var(--card);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.sheet-head {
  padding: 16px var(--sheet-pad);
  border-bottom: 1px solid var(--line);
}

/* The sheet's title, not a document's — `fz="section"`, as `CModal` sets it.
   It is the page's h1 all the same, and the script rewrites it per step
   exactly as the sheet's `TITLES` map does. */
.sheet-head h1 {
  margin: 0;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -0.015em;
}

.sheet-body {
  padding: var(--sheet-pad);
}

.sheet-foot {
  padding: var(--sheet-pad);
  border-top: 1px solid var(--line);
}

/* One step's body, and one step's footer: a column with the sheet's own `md`
   gap, so nothing inside needs a margin of its own. */
[data-step],
[data-foot] {
  display: flex;
  flex-direction: column;
}

[data-step] {
  gap: 16px;
}

/* The footer's buttons sit at `Stack gap="xs"`, as in the sheet. */
[data-foot] {
  gap: 10px;
}

/* The gap owns the vertical rhythm — but only the block margins are cleared,
   since the centred glyph and caption of the last step are centred by their
   own `auto` inline margins. */
[data-step] > * {
  margin-block: 0;
}

/* The step's own lead: a glyph and a line of dimmed text, as every step of the
   sheet opens. */
.step-lead {
  display: flex;
  align-items: center;
  gap: 14px;
}

.step-lead > .ic {
  flex: none;
  width: 30px;
  height: 30px;
  color: var(--faint);
}

/* The step that discloses what is about to be lost. A bare red glyph: the red
   says "destructive" on its own, and a tinted square around it made the step
   open on a badge rather than on the warning. */
.step-lead.warn > .ic {
  color: var(--red);
}

/* Every step opens with one dimmed line — `Text size="hint" c="dimmed"` in the
   sheet — with the fact that matters picked out in ink. */
.lead-text {
  color: var(--ink-soft);
  font-size: 15px;
  line-height: 1.55;
  text-wrap: pretty;
}

.lead-text b {
  color: var(--ink);
  font-weight: 600;
}

.field {
  display: block;
  margin: 0 0 14px;
}

.field > span {
  display: block;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 6px;
}

.field input,
.field textarea {
  width: 100%;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 10px 14px;
  min-height: 42px; /* the app's `size="md"` control height */
}

.field textarea {
  line-height: 1.5;
  resize: vertical;
}

.field input::placeholder,
.field textarea::placeholder {
  color: var(--faint);
}

.field input:focus,
.field textarea:focus {
  outline: 2px solid var(--brand);
  outline-offset: -1px;
  border-color: transparent;
}

/* The OTP field. The app renders four separate cells; a single input keeps
   one-time-code autofill working, so it is spaced and centred to read as
   cells rather than as four digits adrift at the left edge of a wide box. */
.field input.code {
  text-align: center;
  letter-spacing: 0.6em;
  text-indent: 0.6em;
  font-variant-numeric: tabular-nums;
  font-size: 24px;
  font-weight: 700;
  padding: 12px 14px;
  border-radius: var(--r-md);
  background: var(--fill);
  border-color: transparent;
}

/* The resend slot: the countdown, then the link — one fixed-height centred row
   either way, so the step does not jump as it changes. */
.resend {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 28px;
  color: var(--ink-soft);
  font-size: 15px;
}

.resend .ic {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--faint);
}

/* The phone field's country code: a static prefix, deliberately outside the
   input so the digits in the field are unambiguously the national part. */
.phone {
  display: flex;
  align-items: center;
  gap: 10px;
}

.phone .prefix {
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.phone input {
  flex: 1;
  min-width: 0;
  font-variant-numeric: tabular-nums;
}

/* Consent. The one red surface of the confirm step: this is the acknowledgement
   itself, so it is what the red is spent on. The whole card is the label, so
   the tap target is the card. */
.consent,
.optional {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--r-lg);
  margin: 0 0 12px;
  cursor: pointer;
}

.consent {
  background: var(--red-wash);
  box-shadow: inset 0 0 0 1px var(--red-ring);
}

.consent span {
  color: var(--red-strong);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.45;
}

.optional {
  display: block;
  background: var(--fill);
}

.optional > span:first-child {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  color: var(--ink-soft);
  font-size: 15px;
  line-height: 1.45;
}

.consent input[type='checkbox'],
.optional input[type='checkbox'] {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  border-radius: 6px;
  cursor: pointer;
}

.consent input[type='checkbox'] {
  accent-color: var(--red);
}

.optional input[type='checkbox'] {
  accent-color: var(--brand);
}

/* Revealed by the checkbox above it. Same field treatment as `.field`, which
   this one is not inside — it is part of the label, so that tapping the row
   toggles the checkbox. */
.optional textarea {
  display: block;
  width: 100%;
  margin-top: 12px;
  font: inherit;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 10px 14px;
  resize: vertical;
}

.optional textarea::placeholder {
  color: var(--faint);
}

.optional textarea:focus {
  outline: 2px solid var(--brand);
  outline-offset: -1px;
  border-color: transparent;
}

/* ──────────────────────────────  buttons  ────────────────────────────────── */

/* Full width, `radius="lg"`, label at 600 — the sheet's footer buttons. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  min-height: 42px;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  padding: 10px 18px;
  border: 1px solid transparent;
  border-radius: var(--r-lg);
  cursor: pointer;
  background-image: var(--gradient-brand);
  background-origin: border-box;
  box-shadow: var(--shadow-brand);
  color: #fff;
  text-decoration: none;
  transition: filter 0.15s ease;
}

.btn .ic {
  width: 18px;
  height: 18px;
  flex: none;
}

.btn:hover:not([disabled]) {
  filter: brightness(1.08);
}

.btn:active:not([disabled]) {
  filter: brightness(0.94);
}

.btn[disabled] {
  background-image: none;
  background-color: var(--fill);
  box-shadow: none;
  color: var(--faint);
  cursor: not-allowed;
  filter: none;
}

/* Destructive: a flat red, no gradient. The brand gradient is for the action we
   would rather the reader take. */
.btn.danger {
  background-image: none;
  background-color: var(--red);
  box-shadow: none;
  color: #fff;
}

/* `variant="default"` — keeping the account gets equal weight to deleting it,
   which is the outcome we would rather the reader reach. */
.btn.ghost {
  background-image: none;
  background-color: var(--card);
  border-color: var(--line);
  box-shadow: none;
  color: var(--ink);
}

.btn.ghost:hover:not([disabled]) {
  background-color: var(--fill);
  filter: none;
}

.linkbtn {
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  background: none;
  border: 0;
  padding: 0;
  color: var(--brand-fg);
  cursor: pointer;
}

/* ───────────────────────────────  messages  ──────────────────────────────── */

/* The API's own message, under the field or the button it belongs to. */
.error {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 12px 0 0;
  color: var(--red-strong);
  font-size: 15px;
  line-height: 1.5;
}

.error .ic {
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 3px;
}

/* Every glyph on these pages is a 256-box Phosphor path in the fill weight, the
   same set the app draws from — sized by the rule that places it and coloured
   by its container. */
.ic {
  display: block;
  fill: currentColor;
}

/* Figures that change in place — a phone number, a date — must not reflow as
   their digits do. The app's own `.ob-tnum`. */
.ob-tnum {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The line under a finished step's glyph: helper text, centred and kept narrow
   enough to read as a caption rather than as a paragraph. */
.done-text {
  max-width: 420px;
  margin: 0 auto 16px;
  color: var(--ink-soft);
  font-size: 15px;
  line-height: 1.55;
  text-align: center;
  text-wrap: pretty;
}

.done-text b {
  color: var(--ink);
  font-weight: 600;
}

/* The centred glyph a finished step opens with. */
.done-glyph {
  display: block;
  width: 44px;
  height: 44px;
  margin: 4px auto 12px;
  color: var(--faint);
  fill: currentColor;
}
