/* ============================================================
   VERITY — the shared design system for the public pages.

   Extracted from marketing/index.html, which carried all of it inline. Three
   pages now need the same palette, the same header and the same buttons, and
   three inline copies is three chances for the sign-up page to drift into
   looking like a different product than the page that sent them there.

   It is a separate FILE rather than a build step because there is no build
   step here: marketing/ is hand-written HTML the API serves as static files.
   One extra request, cached across all three pages and across deploys.

   WHAT LIVES HERE   tokens, base type, the header, buttons, cards, chips,
                     pills, forms, footer, reduced-motion.
   WHAT DOES NOT     anything a single page uses — the landing page's hero,
                     proof table and CTA band stay inline in index.html.

   Contrast notes are on the token block below and are load-bearing: several
   brand colours are FILLS that fail as text, and the -ink variants exist for
   exactly that reason. Do not use --primary or --accent for text.
   ============================================================ */

/* ============================================================
   Inter — SIL Open Font License 1.1. The interface face.

   Added when the product moved to Inter for chrome and body text. Charis
   stays below as the DISPLAY face: the headlines and the big proof figures,
   where a serif reads as editorial confidence rather than as a legibility
   cost. Everything smaller than a headline is now Inter.

   Weights 400 and 700 only, matching the two the stylesheets actually ask
   for. Ranges are Fontsource's own, so they match the subsetting the files
   were built with; latin-ext carries the Romanian and Hungarian diacritics
   and is fetched only when those code points appear.
   ============================================================ */
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("fonts/inter-latin-400.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: "Inter"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("fonts/inter-latin-ext-400.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("fonts/inter-latin-700.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: "Inter"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("fonts/inter-latin-ext-700.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ============================================================
   Charis SIL — SIL Open Font License 1.1.
   Weights 400 and 700 only: there is no 500/600 face, and asking
   for one makes the browser synthesise a fake bold.
   latin-ext carries the Romanian and Hungarian diacritics.
   ============================================================ */
@font-face {
  font-family: "Charis SIL"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("fonts/charis-latin-ext-400.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Charis SIL"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("fonts/charis-latin-400.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: "Charis SIL"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("fonts/charis-latin-ext-700.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Charis SIL"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("fonts/charis-latin-700.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;
}

/* ============================================================
   TOKENS — complete light palette on bare :root.
   The dark blocks below redefine tokens ONLY; no component is
   ever styled inside them.

   Contrast notes baked into these values:
   · --text-muted (#A5959D) is 2.84:1 on white. It is a BORDER and
     DECORATIVE-MARK token. It is never used for text.
   · --text-secondary (#7A6B72) is 5.03:1 on surface0 but only
     4.26:1 on surface2, so tinted panels use --text-secondary-tint.
   · --primary (#D42A78) is 4.44:1 on --background, so brand-coloured
     TEXT uses --brand-ink (#A62163, 6.48:1). --primary stays a fill.
   · --accent (#E09A2C) is 2.38:1 on white; it tints chips, and the
     amber icon stroke uses --ink-amber (#B87B14, 3.57:1).
   ============================================================ */
:root {
  --background: #FCF5F8;
  --surface0: #FFFFFF;
  --surface1: #FCF9FA;
  --surface2: #F7F1F4;

  --text-primary: #2A1922;
  --text-secondary: #7A6B72;
  --text-secondary-tint: #695A61;   /* secondary text on surface2 / tinted panels */
  --text-muted: #A5959D;            /* borders + decorative marks only — never text */

  --border: #EFE2E8;
  --border-hover: #DFCBD5;

  --primary: #D42A78;
  --primary-hover: #A62163;
  --primary-pressed: #7A1444;
  --primary-muted: #FCE7F0;
  --on-primary: #FFFFFF;
  --on-primary-pressed: #FFFFFF;    /* the pressed fill is dark in both themes */
  --brand-ink: #A62163;             /* brand colour when it must be readable text */

  --accent: #E09A2C;
  --success: #35784A;
  --warning: #B87B14;
  --error: #CE3A2F;

  --ink-pink: #A62163;
  --ink-blue: #3C5DC4;
  --ink-green: #35784A;
  --ink-amber: #B87B14;

  --chip-error-bg: #F9E7E6;
  --chip-success-bg: #E7EFE9;
  --rail: #F1E4EB;
  --bar-neutral: #7A6B72;           /* de-emphasis mark; --text-muted is too faint to carry meaning */

  --cta-from: #A62163;
  --cta-to: #8E1B4C;
  --cta-ink: #FFFFFF;
  --cta-ink-2: #F5D9E6;
  --cta-btn-bg: #FFFFFF;
  --cta-btn-ink: #A62163;

  --glass: rgb(255 255 255 / .82);
  --shadow: 0 1px 2px rgb(42 25 34 / .04), 0 2px 10px rgb(42 25 34 / .05);
  --shadow-hover: 0 2px 4px rgb(42 25 34 / .06), 0 12px 28px rgb(42 25 34 / .10);

  --font-ui: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: "Charis SIL", Georgia, serif;

  --r-card: 16px;
  --r-control: 12px;
  --maxw: 1120px;

  /* ---- depth and atmosphere ------------------------------------------
     Added when the pages were judged "too bland". The diagnosis was not the
     palette — it was that every surface sat on exactly one plane: white cards
     on a near-white ground, one flat border, one flat shadow. Nothing here
     changes a hue. It adds the three things that were missing:

       GLOW    two very wide, very faint brand-tinted radials behind the hero
               and the auth card. At 6-9% they are below the threshold where
               you would call the background "pink" — you only notice that the
               corners of the page are not the same colour as the middle.
       GRID    a 1px rule every 64px, at ~3% contrast, masked to fade out
               before it reaches the content. It gives the eye something to
               measure the layout against, which is most of what makes a
               spacious page read as composed rather than as empty.
       LIFT    a proper elevation ramp. One shadow for everything is why cards
               and buttons looked like the same object.

     All of it is in tokens so dark mode restates the values rather than the
     rules — the glows have to be MUCH stronger in dark (a faint wash on a
     near-black ground is invisible) and the grid much fainter. */
  --glow-brand: rgb(212 42 120 / .09);
  --glow-warm: rgb(224 154 44 / .07);
  --grid-line: rgb(42 25 34 / .035);
  --grid-size: 64px;

  /* A hairline that is lighter than --border, for edges INSIDE a surface —
     a card's top highlight, a divider between two things already grouped.
     Reusing --border there made every seam look like an outer boundary. */
  --hairline: rgb(42 25 34 / .06);
  /* The inner top highlight that makes a filled button look convex. */
  --sheen: rgb(255 255 255 / .16);

  --lift-1: 0 1px 2px rgb(42 25 34 / .04);
  --lift-2: 0 1px 2px rgb(42 25 34 / .05), 0 4px 12px rgb(42 25 34 / .06);
  --lift-3: 0 2px 4px rgb(42 25 34 / .06), 0 12px 28px rgb(42 25 34 / .10);
  --lift-4: 0 4px 8px rgb(42 25 34 / .07), 0 24px 56px rgb(42 25 34 / .14);

  /* The focus ring, once, so every control agrees. */
  --ring: 0 0 0 3px rgb(212 42 120 / .26);

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --background: #171015;
    --surface0: #171015;
    --surface1: #241A20;
    --surface2: #33252C;

    --text-primary: #FAF6F8;
    --text-secondary: #B7A5AE;
    --text-secondary-tint: #B7A5AE;
    --text-muted: #8C7A83;

    --border: #33252C;
    --border-hover: #46333C;

    --primary: #EE5F9B;
    --primary-hover: #D42A78;
    --primary-pressed: #A62163;
    --primary-muted: #4A1230;
    --on-primary: #171015;
    --on-primary-pressed: #FFFFFF;
    --brand-ink: #EE5F9B;

    --accent: #F7C36A;
    --success: #5FC77E;
    --warning: #F0A83C;
    --error: #F2726A;

    --ink-pink: #EE5F9B;
    --ink-blue: #8FA6EE;
    --ink-green: #6FD69A;
    --ink-amber: #E4A93F;

    --chip-error-bg: #41292D;
    --chip-success-bg: #2F3431;
    --rail: #33252C;
    --bar-neutral: #B7A5AE;

    --cta-from: #7A1444;
    --cta-to: #5E1036;
    --cta-ink: #FFFFFF;
    --cta-ink-2: #F0CFDF;
    --cta-btn-bg: #FAF6F8;
    --cta-btn-ink: #7A1444;

    --glass: rgb(36 26 32 / .82);
    --shadow: 0 1px 2px rgb(0 0 0 / .30), 0 2px 10px rgb(0 0 0 / .35);
    --shadow-hover: 0 2px 4px rgb(0 0 0 / .35), 0 12px 28px rgb(0 0 0 / .45);

    /* Restated, not inherited. A wash that reads as a whisper on white is
       invisible on #171015, and a grid that is legible on white is a set of
       scratches on black — so the glows go UP and the grid comes DOWN. */
    --glow-brand: rgb(238 95 155 / .16);
    --glow-warm: rgb(247 195 106 / .10);
    --grid-line: rgb(255 255 255 / .028);
    --hairline: rgb(255 255 255 / .07);
    --sheen: rgb(255 255 255 / .10);

    /* Shadow alone does almost nothing on a dark ground — there is no light for
       it to remove. The elevation ramp leans on the top hairline instead, which
       is why each of these carries an inset highlight rather than more blur. */
    --lift-1: 0 1px 2px rgb(0 0 0 / .35);
    --lift-2: 0 2px 6px rgb(0 0 0 / .40), inset 0 1px 0 rgb(255 255 255 / .04);
    --lift-3: 0 8px 24px rgb(0 0 0 / .50), inset 0 1px 0 rgb(255 255 255 / .05);
    --lift-4: 0 16px 48px rgb(0 0 0 / .60), inset 0 1px 0 rgb(255 255 255 / .06);

    --ring: 0 0 0 3px rgb(238 95 155 / .32);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --background: #171015;
  --surface0: #171015;
  --surface1: #241A20;
  --surface2: #33252C;

  --text-primary: #FAF6F8;
  --text-secondary: #B7A5AE;
  --text-secondary-tint: #B7A5AE;
  --text-muted: #8C7A83;

  --border: #33252C;
  --border-hover: #46333C;

  --primary: #EE5F9B;
  --primary-hover: #D42A78;
  --primary-pressed: #A62163;
  --primary-muted: #4A1230;
  --on-primary: #171015;
  --on-primary-pressed: #FFFFFF;
  --brand-ink: #EE5F9B;

  --accent: #F7C36A;
  --success: #5FC77E;
  --warning: #F0A83C;
  --error: #F2726A;

  --ink-pink: #EE5F9B;
  --ink-blue: #8FA6EE;
  --ink-green: #6FD69A;
  --ink-amber: #E4A93F;

  --chip-error-bg: #41292D;
  --chip-success-bg: #2F3431;
  --rail: #33252C;
  --bar-neutral: #B7A5AE;

  --cta-from: #7A1444;
  --cta-to: #5E1036;
  --cta-ink: #FFFFFF;
  --cta-ink-2: #F0CFDF;
  --cta-btn-bg: #FAF6F8;
  --cta-btn-ink: #7A1444;

  --glass: rgb(36 26 32 / .82);
  --shadow: 0 1px 2px rgb(0 0 0 / .30), 0 2px 10px rgb(0 0 0 / .35);
  --shadow-hover: 0 2px 4px rgb(0 0 0 / .35), 0 12px 28px rgb(0 0 0 / .45);

  /* Restated, not inherited. A wash that reads as a whisper on white is
     invisible on #171015, and a grid that is legible on white is a set of
     scratches on black — so the glows go UP and the grid comes DOWN. */
  --glow-brand: rgb(238 95 155 / .16);
  --glow-warm: rgb(247 195 106 / .10);
  --grid-line: rgb(255 255 255 / .028);
  --hairline: rgb(255 255 255 / .07);
  --sheen: rgb(255 255 255 / .10);

  /* Shadow alone does almost nothing on a dark ground — there is no light for
     it to remove. The elevation ramp leans on the top hairline instead, which
     is why each of these carries an inset highlight rather than more blur. */
  --lift-1: 0 1px 2px rgb(0 0 0 / .35);
  --lift-2: 0 2px 6px rgb(0 0 0 / .40), inset 0 1px 0 rgb(255 255 255 / .04);
  --lift-3: 0 8px 24px rgb(0 0 0 / .50), inset 0 1px 0 rgb(255 255 255 / .05);
  --lift-4: 0 16px 48px rgb(0 0 0 / .60), inset 0 1px 0 rgb(255 255 255 / .06);

  --ring: 0 0 0 3px rgb(238 95 155 / .32);
  color-scheme: dark;
}

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

html {
  overflow-x: clip;               /* clip, not hidden — keeps position:sticky working */
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--background);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 17px;                /* body floor is 16px; nothing on this page goes below it */
  /* 1.6 rather than 1.65: Inter's x-height is larger than Charis's, so the
     same leading reads looser. Measured by eye against the same paragraph. */
  line-height: 1.6;
  font-feature-settings: "cv05" 1;
  -webkit-font-smoothing: antialiased;
}

[id] { scroll-margin-top: 88px; }   /* the sticky header must not cover anchor targets */

/* The display face, and only here. A serif headline over a sans body is the
   pairing this page was already reaching for; what it lacked was the sans.
   h3 and h4 are SMALL headings — card titles, step names — so they stay on
   the interface face where legibility beats character. */
h1, h2 {
  font-family: var(--font-display);
  font-weight: 700; line-height: 1.13; margin: 0;
  letter-spacing: -0.015em; text-wrap: balance;
}
h3, h4 {
  font-weight: 700; line-height: 1.25; margin: 0;
  letter-spacing: -0.01em; text-wrap: balance;
}
p { margin: 0; }
img, svg { max-width: 100%; }

a { color: var(--brand-ink); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--primary-pressed); }

:where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: 6px;
}

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: 20px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; left: 12px; top: -60px; z-index: 60;
  background: var(--surface0); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: var(--r-control);
  padding: 10px 16px; box-shadow: var(--shadow);
}
.skip:focus { top: 12px; }

.i { width: 21px; height: 21px; flex: none; display: block; }
.i-sm { width: 18px; height: 18px; flex: none; display: block; }

/* ============================================================
   HEADER — the only glassmorphic surface on the page.
   All header text is --text-primary, so it stays far above 4.5:1
   whatever scrolls beneath the translucent layer.
   ============================================================ */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--glass);
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
  backdrop-filter: blur(16px) saturate(1.5);
  border-bottom: 1px solid var(--border);
}
.header-in { display: flex; align-items: center; gap: 16px; min-height: 68px; }

.wordmark {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 21px; font-weight: 700; letter-spacing: -0.02em;
  color: var(--text-primary); text-decoration: none; margin-right: auto;
}
.wordmark .mark { color: var(--brand-ink); width: 26px; height: 26px; }

.nav { display: none; gap: 6px; align-items: center; }
.nav a {
  color: var(--text-primary); text-decoration: none;
  padding: 8px 12px; border-radius: 10px; font-size: 16px;
}
.nav a:hover { background: var(--surface2); }
@media (min-width: 860px) { .nav { display: flex; } }

/* Header auth: a quiet text link for people who already have an account, and
   the one filled button on the page for people who do not. Two buttons of
   equal weight here would make the header compete with the hero, which is
   where the actual decision is meant to be made.

   Both are hidden below 560px, where the wordmark and the theme toggle
   already fill the row — the hero's own button is one scroll away and the
   header is not the place to fight for those 40 pixels. */
.nav-signin {
  color: var(--text-primary); text-decoration: none;
  padding: 8px 12px; border-radius: 10px; font-size: 16px; font-weight: 700;
  display: none;
}
.nav-signin:hover { background: var(--surface2); color: var(--text-primary); }

.btn-sm { min-height: 42px; padding: 8px 16px; font-size: 16px; }
.nav-cta { display: none; }

@media (min-width: 560px) {
  .nav-signin, .nav-cta { display: inline-flex; }
}

.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 42px; padding-inline: 12px;
  background: var(--surface0); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: var(--r-control);
  font: inherit; font-size: 16px; cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, transform 100ms ease;
}
.theme-toggle:hover { border-color: var(--border-hover); background: var(--surface1); }
.theme-toggle:active { transform: scale(.97); }
.theme-toggle .label { display: none; }
@media (min-width: 640px) { .theme-toggle .label { display: inline; } }

/* Light shows the moon ("go dark"); dark shows the sun ("go light"). */
.icon-moon { display: block; }
.icon-sun  { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .icon-moon { display: none; }
  :root:not([data-theme="light"]) .icon-sun  { display: block; }
}
:root[data-theme="dark"] .icon-moon { display: none; }
:root[data-theme="dark"] .icon-sun  { display: block; }
:root[data-theme="light"] .icon-moon { display: block; }
:root[data-theme="light"] .icon-sun  { display: none; }

/* ============================================================
   BUTTONS
   ============================================================ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 50px; padding: 12px 22px;
  border-radius: var(--r-control); border: 1px solid transparent;
  font: inherit; font-size: 17px; font-weight: 700; text-decoration: none;
  cursor: pointer; text-align: center;
  transition: background 140ms ease, border-color 140ms ease, box-shadow 140ms ease, transform 100ms ease;
}
.btn:active { transform: scale(.97); }
.btn-primary { background: var(--primary); color: var(--on-primary); box-shadow: var(--shadow); }
.btn-primary:hover { background: var(--primary-hover); color: var(--on-primary); box-shadow: var(--shadow-hover); }
.btn-primary:active { background: var(--primary-pressed); color: var(--on-primary-pressed); }
.btn-ghost {
  background: var(--surface0); color: var(--text-primary);
  border-color: var(--border); box-shadow: var(--shadow);
}
.btn-ghost:hover { border-color: var(--border-hover); background: var(--surface1); color: var(--text-primary); }
.btn-on-band { background: var(--cta-btn-bg); color: var(--cta-btn-ink); }
.btn-on-band:hover { background: var(--cta-btn-bg); color: var(--cta-btn-ink); box-shadow: var(--shadow-hover); }

/* ============================================================
   SHARED SECTION FURNITURE
   ============================================================ */
section { padding-block: clamp(56px, 8vw, 104px); }
/* The section label.
   
   Was a tinted pill with a pulsing dot in it. Both were wrong for this page.
   The dot is the "live status" idiom borrowed from dashboards and status
   pages, where it means something is happening right now; here nothing was
   happening, so it was decoration that blinked — and five of them down one
   page is five things competing with the headings they were labelling.
   
   The pill was the deeper mistake. This page's own visual idiom is the
   MEASURING RULE: the brand mark is a V with a level line struck inside it,
   each stat tile hangs from a short gradient rule, the auth card has one
   across its top, and the whole proof section is bars read against a common
   scale. A rounded chip with a background is from a different vocabulary
   altogether — it is the generic SaaS badge, and it was the only element on
   the page that did not belong to the rest of it.
   
   So the label is now a rule and a word. Same gradient as .stat::before and
   .auth-card::before, deliberately: it should read as the same object
   appearing at a different size, not as a fourth kind of accent. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 13px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  /* --brand-ink, not --primary: the palette notes at the top of this file are
     explicit that --primary is a FILL and fails as text at 4.44:1. This is
     6.48:1 on the page ground. */
  color: var(--brand-ink);
}
.eyebrow::before {
  content: "";
  flex: none;
  width: 30px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--primary), var(--accent));
}
.section-head { max-width: 62ch; margin-bottom: clamp(32px, 5vw, 52px); }
/* 22px, up from 18: the label above lost the 6px of padding its pill
   carried, so the same margin measured tighter than it used to look. */
.section-head h2 { font-size: clamp(28px, 4.4vw, 42px); margin-block: 22px 16px; }
.section-head p { color: var(--text-secondary); font-size: clamp(17px, 2vw, 19px); }

.card {
  background: var(--surface0);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  padding: clamp(22px, 3vw, 30px);
  transition: box-shadow 180ms ease, border-color 180ms ease, transform 180ms ease;
}

/* Tinted icon chip — 44px rounded square, 21px stroke icon in the accent */
.chip-icon {
  width: 44px; height: 44px; border-radius: 13px;
  display: inline-flex; align-items: center; justify-content: center;
  margin-bottom: 18px;
}
.chip-icon.pink  { background: color-mix(in srgb, var(--ink-pink) 12%, transparent);  color: var(--ink-pink); }
.chip-icon.blue  { background: color-mix(in srgb, var(--ink-blue) 12%, transparent);  color: var(--ink-blue); }
.chip-icon.green { background: color-mix(in srgb, var(--ink-green) 12%, transparent); color: var(--ink-green); }
.chip-icon.amber { background: color-mix(in srgb, var(--accent) 12%, transparent);    color: var(--ink-amber); }

/* Status pill — colour is never the only channel: icon + word + colour */
.pill {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 16px; font-weight: 700;
  border-radius: 999px; padding: 5px 13px 5px 10px;
  color: var(--text-primary);
  border: 1px solid var(--border);
}
.pill.bad  { background: var(--chip-error-bg); }
.pill.good { background: var(--chip-success-bg); }
.pill.bad .i-sm  { color: var(--error); }
.pill.good .i-sm { color: var(--success); }


.site-footer { border-top: 1px solid var(--border); padding-block: 36px; margin-top: clamp(56px, 8vw, 104px); }
.footer-in { display: flex; flex-wrap: wrap; gap: 16px 28px; align-items: center; justify-content: space-between; }
.site-footer p { color: var(--text-secondary); font-size: 16px; }


/* ============================================================
   THE VISUAL SYSTEM
   ============================================================

   Everything below was added in one pass, against one complaint: the pages
   were correct, accessible, well-typeset — and flat. Worth writing down what
   the fix was, because the instinct in that situation is to reach for a
   brighter colour, and a brighter colour would have been the wrong answer.

   The problem was never hue. It was that the page had ONE plane. White cards
   on a near-white ground, every edge the same 1px --border, every raised
   thing wearing the same shadow. Nothing was nearer than anything else, so
   the eye had nothing to travel over and read the whole composition as a
   wireframe of itself.

   So: no new hues. Depth instead —

     1. an ambient ground: two very wide brand radials and a faint measuring
        grid, so the page has weather rather than a fill;
     2. a real elevation ramp, so a button, a card and a modal are three
        distances rather than one;
     3. edges that mean something: --hairline inside a surface, --border at
        its boundary, a --sheen highlight only on things that are filled;
     4. motion that acknowledges the pointer — 120ms, small, and gone under
        prefers-reduced-motion.

   RESTRAINT IS THE SPEC, not a caveat on it. Every glow here is under 16%
   and every grid line under 4%. The test is that you should not be able to
   name what changed — the page should read as composed, and a visitor asked
   what colour the background is should still say "white".
   ============================================================ */

/* ---- the brand mark's second colour ---------------------------------
   The measuring rule struck through the V. Accent rather than the brand pink:
   at 26px two shades of the same hue turn to mud, and the rule needs to read
   as a DIFFERENT thing from the letter, not a lighter part of it. */
.mk-rule { color: var(--accent); stroke: var(--accent); }
.wordmark:hover .mk-rule { color: var(--primary); stroke: var(--primary); }
.mk-rule { transition: stroke 200ms ease; }

/* ---- ambient ground --------------------------------------------------
   One element, fixed, behind everything, painting the glows and the grid.

   FIXED rather than absolute so it does not scroll: the glow belongs to the
   viewport, like light in a room, and a wash that scrolls away reads as a
   graphic somebody put on the page. aria-hidden and pointer-events:none —
   it is atmosphere, and nothing should ever be able to click or read it.

   The grid is masked to fade before it reaches the middle of the screen,
   because a grid that runs under body text is texture behind words and makes
   them harder to read for exactly the people who find reading hardest. */
.ambient {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(58rem 32rem at 12% -8%, var(--glow-brand), transparent 62%),
    radial-gradient(46rem 28rem at 92% 4%, var(--glow-warm), transparent 60%),
    var(--background);
}

/* The grid, as a child so it can carry its own mask without affecting the
   glows above it. */
.ambient::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: var(--grid-size) var(--grid-size);
  /* Strongest at the top, gone by a third of the way down — the hero is where
     it does its work, and below that the content provides its own structure. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 38%);
  mask-image: linear-gradient(to bottom, #000 0%, transparent 38%);
}

/* Sections that sit ON the ambient ground must not paint over it. .proof
   deliberately still does — it is the centrepiece and earns a solid plate. */
body { background: transparent; }

/* ---- header ----------------------------------------------------------- */
.site-header {
  /* The glass was already here; what it lacked was a bottom edge that reads
     as an edge. A hairline over the border gives it a lit lip rather than a
     drawn line. */
  box-shadow: 0 1px 0 var(--hairline);
}

.wordmark .mark {
  /* A hair larger, and it now leans very slightly on hover. Two degrees is
     under the threshold of "an animation" and over the threshold of "this
     responds to me". */
  width: 28px; height: 28px;
  transition: transform 240ms cubic-bezier(.2, .8, .2, 1);
}
.wordmark:hover .mark { transform: rotate(-4deg) scale(1.04); }

/* ---- buttons ---------------------------------------------------------- */
.btn {
  position: relative;
  /* Was 140ms on three properties. Shorter, and on transform too, so a press
     feels mechanical rather than syrupy. */
  transition: background 120ms ease, border-color 120ms ease,
              box-shadow 160ms ease, transform 120ms cubic-bezier(.2, .8, .2, 1);
}

.btn-primary {
  /* A gradient of two stops six percent apart. Not a "gradient button" — at
     this distance it reads as a single colour lit from above, which is what
     stops a large flat fill looking like a coloured rectangle. */
  background: linear-gradient(180deg, var(--primary), var(--primary-hover));
  box-shadow: var(--lift-2), inset 0 1px 0 var(--sheen);
}
.btn-primary:hover {
  background: linear-gradient(180deg, var(--primary-hover), var(--primary-pressed));
  box-shadow: var(--lift-3), inset 0 1px 0 var(--sheen);
  transform: translateY(-1px);
}
.btn-primary:active {
  background: var(--primary-pressed);
  transform: translateY(0) scale(.985);
  box-shadow: var(--lift-1);
}

.btn-ghost { box-shadow: var(--lift-1); }
.btn-ghost:hover {
  box-shadow: var(--lift-2);
  transform: translateY(-1px);
}
.btn-ghost:active { transform: translateY(0) scale(.985); }

/* The arrow inside a button steps forward on hover. It is 3px and it is the
   difference between a label and an invitation. */
.btn svg { transition: transform 200ms cubic-bezier(.2, .8, .2, 1); }
.btn:hover svg { transform: translateX(3px); }

/* One focus treatment for every control on the site. The outline stays —
   it is what survives forced-colors mode, where box-shadow is discarded —
   and the ring is added underneath it for everyone else. */
:where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  box-shadow: var(--ring);
}

/* ---- cards ------------------------------------------------------------ */
.card {
  position: relative;
  box-shadow: var(--lift-2);
  /* A lit top edge. One inset hairline is what separates a card from a
     rectangle with a border, and it costs nothing. */
  border-top-color: var(--hairline);
  transition: box-shadow 220ms ease, transform 220ms cubic-bezier(.2, .8, .2, 1),
              border-color 220ms ease;
}

/* Hover lift is opt-in: .proof's two panels are being COMPARED, and a panel
   that rises when the pointer crosses it suggests the pointer is choosing
   between them. Applied to .feature and the stat tiles, which are links or
   list items and where it reads as affordance. */
/* Its own transition rather than .card's: .lift is also used on the stat
   tiles, which are not cards, and without this they snapped instead of
   moving. */
.lift {
  transition: box-shadow 220ms ease,
              transform 220ms cubic-bezier(.2, .8, .2, 1),
              border-color 220ms ease;
}
.lift:hover {
  transform: translateY(-3px);
  box-shadow: var(--lift-3);
  border-color: var(--border-hover);
}

/* ---- chip icons -------------------------------------------------------
   The single biggest bland-maker: a flat 12%-tint square behind a stroke
   icon, four times down the page in four hues. They now have a soft vertical
   tint, a ring in their own colour, and a shadow — so they read as objects
   sitting on the card rather than as swatches printed on it. */
.chip-icon {
  border-radius: 14px;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .5),
    0 2px 6px rgb(42 25 34 / .06);
  transition: transform 240ms cubic-bezier(.2, .8, .2, 1);
}
.chip-icon.pink {
  background: linear-gradient(160deg,
              color-mix(in srgb, var(--ink-pink) 18%, transparent),
              color-mix(in srgb, var(--ink-pink) 8%, transparent));
  outline: 1px solid color-mix(in srgb, var(--ink-pink) 20%, transparent);
  outline-offset: -1px;
}
.chip-icon.blue {
  background: linear-gradient(160deg,
              color-mix(in srgb, var(--ink-blue) 18%, transparent),
              color-mix(in srgb, var(--ink-blue) 8%, transparent));
  outline: 1px solid color-mix(in srgb, var(--ink-blue) 20%, transparent);
  outline-offset: -1px;
}
.chip-icon.green {
  background: linear-gradient(160deg,
              color-mix(in srgb, var(--ink-green) 18%, transparent),
              color-mix(in srgb, var(--ink-green) 8%, transparent));
  outline: 1px solid color-mix(in srgb, var(--ink-green) 20%, transparent);
  outline-offset: -1px;
}
.chip-icon.amber {
  background: linear-gradient(160deg,
              color-mix(in srgb, var(--accent) 22%, transparent),
              color-mix(in srgb, var(--accent) 9%, transparent));
  outline: 1px solid color-mix(in srgb, var(--accent) 24%, transparent);
  outline-offset: -1px;
}
/* The inset white highlight is light bouncing off a top edge; on a dark
   ground there is no such light, and leaving it in put a grey scuff on every
   chip. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .chip-icon {
    box-shadow: inset 0 1px 0 rgb(255 255 255 / .06), 0 2px 8px rgb(0 0 0 / .4);
  }
}
:root[data-theme="dark"] .chip-icon {
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .06), 0 2px 8px rgb(0 0 0 / .4);
}

.lift:hover .chip-icon { transform: scale(1.06) rotate(-3deg); }

/* ---- pills ------------------------------------------------------------ */
.pill {
  box-shadow: var(--lift-1);
  border-color: var(--hairline);
}

/* ---- reveal on scroll -------------------------------------------------
   Driven by motion.js. The class is added by script, so a page with no
   JavaScript never hides anything — the content is visible by default and
   the animation is the enhancement, not the other way round. That ordering
   is the whole reason this is safe.
   ---------------------------------------------------------------------- */
.js-reveal { opacity: 0; transform: translateY(14px); }
.js-reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 620ms cubic-bezier(.2, .8, .2, 1),
              transform 620ms cubic-bezier(.2, .8, .2, 1);
}


/* ============================================================
   AUTH, SECOND PASS

   The first version was a white card centred on a white page. Correct, and
   the single blandest screen on the site — it is also the screen where a
   stranger decides whether this looks like a real product, so it was the
   worst place to be forgettable.

   What it gets now, in order of how much each does:

     · a brand lockup at the top of the card, so the page identifies itself
       above the fold rather than only in the header;
     · a glow behind the card, brighter than the ambient one, which makes the
       card the lit object in the frame instead of a white shape on white;
     · a gradient top edge on the card — three pixels of brand, the only
       saturated colour on the screen, and the thing your eye lands on first;
     · inputs that are objects rather than outlines: a recessed fill, a real
       focus ring, and a floating-free label with room to breathe.

   Still restrained. There is no illustration, no photograph, no gradient
   mesh: it is a form, and the fastest possible path through it is the point.
   ============================================================ */

.auth-main {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

/* The pool of light the card sits in. Wider and softer than the card so it
   reads as illumination rather than as a coloured border around it. */
.auth-main::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -8%;
  /* 100%, not 130vw. The glow is centred on the container and translated back
     by half its own width, so anything wider than the container hangs off BOTH
     sides — at 420px that was 63px of overhang each way, and because it is a
     positioned element in normal flow it made the whole document scroll
     sideways on every phone. A decorative wash that adds a horizontal
     scrollbar is a straightforward bug, and it was invisible on a desktop
     because 130vw only exceeds 760px below 585px wide. */
  width: min(760px, 100%);
  aspect-ratio: 1.35;
  transform: translateX(-50%);
  background: radial-gradient(closest-side,
              color-mix(in srgb, var(--primary) 15%, transparent),
              transparent 72%);
  pointer-events: none;
  z-index: 0;
}

.auth-wrap { position: relative; z-index: 1; width: 100%; max-width: 448px; padding-inline: 20px; }

/* ---- the card --------------------------------------------------------- */
.auth-card {
  position: relative;
  overflow: hidden;                 /* clips the top edge to the radius */
  background: var(--surface0);
  border: 1px solid var(--border);
  border-top-color: var(--hairline);
  border-radius: var(--r-card);
  box-shadow: var(--lift-4);
  padding: clamp(28px, 4vw, 40px);
}

/* Three pixels of brand across the top. The only fully saturated colour on
   the screen, which is what makes it the entry point for the eye. */
.auth-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: linear-gradient(90deg,
              var(--primary), var(--accent) 60%, var(--primary));
}

/* ---- the lockup ------------------------------------------------------- */
.auth-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 22px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  text-decoration: none;
}
.auth-brand .mark { width: 27px; height: 27px; color: var(--brand-ink); }

/* The offer, said once, in the one place it changes a decision.
   
   A filled chip here rather than the .eyebrow rule used for section labels,
   and the difference is deliberate: an eyebrow NAMES the section under it,
   while this makes a claim of its own. It is also the one place on the site
   where a badge is the right idiom — it is a price, and a price is a thing
   people expect to find in a tag. */
.auth-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 16px;
  padding: 5px 12px 5px 10px;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--accent) 20%, transparent),
              color-mix(in srgb, var(--accent) 10%, transparent));
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
}
.auth-badge svg { width: 16px; height: 16px; color: var(--ink-amber); }

.auth-card h1 { font-size: clamp(27px, 3.4vw, 32px); margin-bottom: 9px; }
.auth-lede { color: var(--text-secondary); font-size: 17px; margin-bottom: 26px; }

/* ---- fields -----------------------------------------------------------
   The input was a 1px outline on the card's own background, which made it a
   drawn rectangle rather than a place to put something. --surface1 recesses
   it very slightly, so it reads as a well. */
.field { display: block; margin-bottom: 18px; }
.field > .label {
  display: block;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .01em;
  color: var(--text-primary);
  margin-bottom: 8px;
}
.field input {
  width: 100%;
  height: 52px;
  padding: 0 15px;
  background: var(--surface1);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--r-control);
  font: inherit;
  font-size: 17px;
  transition: border-color 140ms ease, box-shadow 160ms ease, background 140ms ease;
}
.field input::placeholder { color: var(--text-secondary); opacity: .5; }
.field input:hover { border-color: var(--border-hover); }
.field input:focus {
  outline: none;
  background: var(--surface0);
  border-color: var(--primary);
  /* Ring, not just a border swap: on the tinted dark surface a 1px colour
     change is close to invisible, and focus has to be unmistakable for
     anyone driving this from the keyboard. */
  box-shadow: var(--ring);
}
.field input[aria-invalid="true"] { border-color: var(--error); }
.field input[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--error) 24%, transparent);
}

.field-hint {
  display: block;
  min-height: 22px;
  margin-top: 6px;
  font-size: 15px;
  color: var(--text-secondary);
}
.field-hint[data-error="true"] { color: var(--error); font-weight: 700; }

.auth-rule {
  font-size: 15px;
  color: var(--text-secondary);
  margin: -8px 0 20px;
}

.auth-card .btn-primary {
  width: 100%;
  margin-top: 4px;
  height: 52px;
  font-size: 17px;
}

/* ---- messages ---------------------------------------------------------- */
/* A message from the server, said the way this site says everything else.

   IT USED TO HAVE A 3px RED BAR DOWN ITS LEFT EDGE. That is the callout
   idiom — Bootstrap alerts, documentation admonitions — and it belongs to a
   different design language than the rest of these pages. Nothing else here
   puts a slab of colour on one side of anything: the auth card carries a
   3px accent across its TOP, a stat tile hangs from a short rule, a section
   label sits beside one, and every inline status on the site is a .pill or an
   .auth-note — a tint, a hairline, and an icon.

   So this is now built from the same three parts as .auth-note directly below
   it, which is the component it sits closest to on the page.

   THE ICON IS NOT DECORATION. The palette notes at the top of this file say
   colour is never the only channel, and with the bar gone the tint alone is a
   weak signal — chip-error-bg is a 4% wash. Icon, colour and wording now
   carry it together, which is also what makes it legible to somebody who
   cannot separate the red from the grey. */
.auth-error {
  display: none;
  gap: 11px;
  align-items: flex-start;
  background: var(--chip-error-bg);
  /* Faintly error-tinted rather than the neutral --hairline: it is still a
     hairline, but it belongs to the message rather than to the box. */
  border: 1px solid color-mix(in srgb, var(--error) 24%, transparent);
  border-radius: var(--r-control);
  padding: 13px 15px;
  margin-bottom: 20px;
  font-size: 16px;
  color: var(--text-primary);
}
.auth-error[data-shown="true"] { display: flex; }

.auth-error-icon {
  width: 18px; height: 18px; flex: none; margin-top: 3px;
  color: var(--error);
}

/* The same box saying something that is NOT a failure — a session that simply
   ran out. Red would tell somebody they did something wrong when they did
   not, so the tint, the border and the icon all step back to neutral, and the
   glyph changes from a warning triangle to an information mark.

   Swapped in CSS rather than in script, the same way the theme toggle picks
   between its sun and its moon: both glyphs are in the markup and the state
   decides which is displayed. That keeps auth.js writing text and nothing
   else — it never has to know what an icon is. */
.auth-error .ico-notice { display: none; }
.auth-error[data-notice="true"] .ico-alert  { display: none; }
.auth-error[data-notice="true"] .ico-notice { display: block; }

.auth-error[data-notice="true"] {
  background: var(--surface2);
  border-color: var(--hairline);
}
.auth-error[data-notice="true"] .auth-error-icon { color: var(--text-secondary); }

/* ---- footer of the card ------------------------------------------------ */
.auth-alt {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--hairline);
  font-size: 16px;
  color: var(--text-secondary);
  text-align: center;
}
.auth-alt a { font-weight: 700; }

.auth-note {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  margin-top: 22px;
  padding: 14px 16px;
  background: var(--surface1);
  border: 1px solid var(--hairline);
  border-radius: var(--r-control);
  font-size: 15px;
  color: var(--text-secondary);
}
.auth-note svg { width: 17px; height: 17px; flex: none; margin-top: 3px; color: var(--ink-green); }

.auth-foot {
  text-align: center;
  margin-top: 26px;
  font-size: 15px;
  color: var(--text-secondary);
}

/* ---- the reasons under the sign-up card -------------------------------- */
.auth-reasons {
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
  display: grid;
  gap: 13px;
}
.auth-reasons li {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  font-size: 16px;
  color: var(--text-secondary);
}
.auth-reasons svg {
  width: 19px; height: 19px; flex: none; margin-top: 3px;
  color: var(--ink-green);
}
.auth-reasons strong { color: var(--text-primary); font-weight: 700; }


/* ============================================================
   REDUCED MOTION

   LAST IN THE FILE, and that position is the point. It was sitting in the
   middle, above the visual system — so the reveal on scroll and every new
   hover transform were declared AFTER the block that
   was supposed to switch them off, and won on source order. A reduced-motion
   rule that is quietly overridden is worse than none: the setting is there
   because motion makes some people ill, and the page would have said it
   honoured the preference while ignoring it.

   The blanket rule kills durations. The named rules below it kill the
   TRANSFORMS as well — a 0.001ms transition still moves the thing, just
   instantly, and an element that teleports is exactly the jump the setting
   is asking us not to make.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  /* No displacement at all, at any point in an interaction. */
  .feature:hover,
  .lift:hover,
  .btn:hover, .btn:active,
  .btn-primary:hover, .btn-primary:active,
  .btn-ghost:hover, .btn-ghost:active,
  .theme-toggle:active,
  .wordmark:hover .mark,
  .lift:hover .chip-icon,
  .btn:hover svg {
    transform: none;
  }

  /* The reveal must not leave content invisible. motion.js does not observe
     anything when this preference is set, so `is-in` may never be added —
     which would hide the page permanently behind an animation that was
     switched off. Belt and braces: visible regardless of the class. */
  .js-reveal, .js-reveal.is-in {
    opacity: 1;
    transform: none;
    transition: none;
  }
}


/* ============================================================
   TOUCH

   The app has its own version of this in web/src/styles/app.css; these three
   pages load verity.css and nothing else, so the rules have to exist here too.
   The audit found the header wordmark at 34px tall, the theme toggle at 42 and
   the sign-in link at 42 — all just under what a fingertip reliably hits, and
   all on the pages a stranger meets first.

   Keyed on `pointer: coarse`, which asks whether a finger is driving this,
   rather than on width — a phone in landscape is 900px wide and still a
   finger, and a narrow desktop window is not one.
   ============================================================ */
@media (pointer: coarse) {
  /* 44px is the size a fingertip can reliably hit. min-height rather than
     height, so anything already larger is untouched. */
  .btn, .theme-toggle, .nav-signin, .nav a, button, select, input {
    min-height: 44px;
  }
  .theme-toggle { min-width: 44px; }

  /* The two wordmarks are links, and therefore targets. They are text, so they
     are given room rather than a fixed height — a height would push them out
     of line with everything else in the header. */
  .wordmark, .auth-brand { padding-block: 6px; }

  /* THE iOS ZOOM TRAP. Safari zooms the page when a control below 16px takes
     focus and never zooms back, leaving the visitor at 1.5x with a sideways
     scrollbar. On the sign-up form specifically, that is the first thing a new
     account holder would experience. */
  input, select, textarea { font-size: 16px; }
}
