/* Self-hosted fonts.
 *
 * Previously these loaded from fonts.googleapis.com / fonts.gstatic.com,
 * which sent every visitor's IP address and user agent to Google on every
 * page load, with no consent and no legal basis. A German court held that
 * unlawful (LG Muenchen I, 3 O 17493/20, 20 January 2022). Serving the
 * files from our own origin removes the third party outright.
 *
 * All three families are licensed under the SIL Open Font License 1.1,
 * which expressly permits redistribution and web hosting. Licence text and
 * per-family provenance are in /fonts/OFL.txt.
 *
 * Fraunces and Inter are variable fonts: Google serves one file across the
 * whole weight range, so they are declared once with a range rather than
 * downloaded three times each. IBM Plex Mono ships a real file per weight.
 *
 * Latin and Latin Extended subsets only. The site is English; Latin
 * Extended covers accented European names. Regenerate with
 * scripts/fetch-fonts.py if the weights used in styles.css change.
 */

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 500 900;
  font-display: swap;
  src: url('/fonts/fraunces-var500-900-latin-ext.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: 'Fraunces';
  font-style: normal;
  font-weight: 500 900;
  font-display: swap;
  src: url('/fonts/fraunces-var500-900-latin.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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-400-latin-ext.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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-400-latin.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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-500-latin-ext.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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-500-latin.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 600;
  font-display: swap;
  src: url('/fonts/inter-var400-600-latin-ext.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: 400 600;
  font-display: swap;
  src: url('/fonts/inter-var400-600-latin.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;
}

/* ============================================================
   Personal Policy — design system
   Shared by the homepage, /about, the legal pages, and the audit.
   Restraint first: whitespace and type do the work, not boxes.

   Motion rules, so the site keeps feeling like one thing:
     - One easing for things arriving (--ease-out), one for things
       settling (--ease). Nothing bounces.
     - Arrivals are slow-ish (400–550ms), departures are quick (160ms).
       The eye forgives a slow entrance and resents a slow exit.
     - Every press has a physical answer: a 2% scale, 80ms, no colour
       flash. Touch gets the same answer as a mouse.
     - Anything that moves respects prefers-reduced-motion, in full.
   ============================================================ */

:root {
  /* Surfaces & ink */
  --paper: #f6f4ef;
  --paper-dim: #efece4;
  --paper-raised: #f1eee7;
  --paper-blur: rgba(246, 244, 239, 0.78);
  --ink: #191714;
  --ink-soft: #524d45;
  --ink-faint: #6e695d;   /* AA: 4.97:1 on --paper, 4.63:1 on --paper-dim */

  /* The one accent. Reserved for actions, focus, and selection. */
  --signal: #a63a2c;
  --signal-soft: #a63a2c14;
  --signal-wash: rgba(166, 58, 44, 0.035);

  /* Hairlines — low-opacity, never solid slabs */
  --rule: rgba(25, 23, 20, 0.11);
  --rule-strong: rgba(25, 23, 20, 0.18);

  --shadow-lift: 0 8px 24px -10px rgba(25, 23, 20, 0.28);
  --shadow-rest: 0 1px 2px rgba(25, 23, 20, 0.05);

  /* Type */
  --serif: "Fraunces", Georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;

  /* Layout — chrome and content share one set of edges, so the brand in
     the header lines up exactly with the headline beneath it. */
  --max: 680px;
  --gutter: 32px;

  /* Vertical rhythm. Every gap on the site is one of these. */
  --space-para: 20px;     /* between paragraphs */
  --space-block: 32px;    /* between a heading's block and a list/form */
  --space-section: clamp(56px, 7vw, 88px);

  /* Motion */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-press: 80ms;
  --dur-leave: 160ms;
  --dur-enter: 480ms;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #17140f;
    --paper-dim: #1e1a14;
    --paper-raised: #201c16;
    --paper-blur: rgba(23, 20, 15, 0.78);
    --ink: #f2ede2;
    --ink-soft: #c6bfb1;
    --ink-faint: #948a7a;   /* AA: 5.40:1 on --paper, 4.98:1 on --paper-raised */

    --signal: #e0684f;
    --signal-soft: #e0684f1f;
    --signal-wash: rgba(224, 104, 79, 0.05);

    --rule: rgba(242, 237, 226, 0.13);
    --rule-strong: rgba(242, 237, 226, 0.2);

    --shadow-lift: 0 8px 24px -10px rgba(0, 0, 0, 0.6);
    --shadow-rest: 0 1px 2px rgba(0, 0, 0, 0.25);
  }
}

* { box-sizing: border-box; }

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

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
}

body {
  overflow-wrap: break-word;
  font-family: var(--sans);
  font-size: clamp(17px, 0.45vw + 15.6px, 18px);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-optical-sizing: auto;
}

::selection {
  background: var(--signal-soft);
  color: var(--ink);
}

/* Mobile browsers paint their own grey flash on tap. Every pressable
   thing on this site has its own press state instead. */
a, button, label, input, textarea, summary {
  -webkit-tap-highlight-color: transparent;
}
button, input, textarea { touch-action: manipulation; }

/* A single, barely-there warm wash behind every page.
   Not a gradient people should notice — one they'd miss if removed. */
body::before {
  content: "";
  position: fixed;
  inset: 0 0 auto 0;
  height: 70vh;
  background: radial-gradient(110% 70% at 50% 0%, var(--signal-wash) 0%, transparent 68%);
  pointer-events: none;
  z-index: 0;
}
/* Lift content above the wash — but never the header, whose own
   position: sticky must survive (a blanket `> *` rule outranks it). */
body > main,
body > footer {
  position: relative;
  z-index: 1;
}

/* ---- Type ------------------------------------------------- */

h1, h2 {
  font-family: var(--serif);
  font-weight: 600;
  margin: 0 0 20px;
  text-wrap: balance;
}
h1 {
  font-size: clamp(32px, 4.4vw, 46px);
  line-height: 1.06;
  letter-spacing: -0.022em;
  margin-bottom: 24px;
}
h2 {
  font-size: clamp(25px, 2.6vw, 32px);
  line-height: 1.15;
  letter-spacing: -0.018em;
}

p {
  margin: 0 0 var(--space-para);
  text-wrap: pretty;
}
ul, ol { margin: 0 0 var(--space-para); }

.kicker {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 18px;
}
/* A dateline directly under a page title (the legal pages) sits close
   to the title it belongs to, not floating between title and lede. */
h1 + .kicker {
  margin: -8px 0 28px;
}

.lede {
  font-size: clamp(19px, 1.1vw + 16px, 21px);
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 0 0 22px;
  letter-spacing: -0.008em;
}

.quote {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(20px, 2vw, 23px);
  line-height: 1.4;
  color: var(--ink);
  margin: 0 0 32px;
  text-wrap: pretty;
}

.prewrap { white-space: pre-line; }

a { color: inherit; }

/* ---- Focus (visible only for keyboard users) --------------- */

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

/* WCAG 2.2 SC 2.4.11, Focus Not Obscured. Every page has a sticky
   header, so an element the browser scrolls into view on Tab can end up
   underneath it. This keeps the header's height clear beneath it. */
:where(a, button, input, textarea, [tabindex]) {
  scroll-margin-top: 96px;
}

/* ---- Page transitions -------------------------------------- */
/* Arriving: the page content rises into place under a header that
   never moves. Leaving: site.js adds .is-leaving to <html> on any
   same-site link click and navigates once the content has faded. The
   header stays put through both, which is what makes it read as one
   continuous site rather than a sequence of reloads. */

@keyframes page-enter {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
/* fill-mode backwards, not both: once the animation ends the element
   must be free to transition out again. */
.site-main {
  animation: page-enter var(--dur-enter) var(--ease-out) backwards;
}
body > main,
body > footer {
  transition:
    opacity var(--dur-leave) var(--ease),
    transform var(--dur-leave) var(--ease);
}
html.is-leaving body > main,
html.is-leaving body > footer {
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
}

/* ---- Scroll reveals ---------------------------------------- */
/* Hidden state applies only once JS confirms it can reveal them. */

.js-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(14px);
}
.js-reveal [data-reveal].is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}

/* ---- Buttons ----------------------------------------------- */

.btn {
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.005em;
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 15px 26px;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition:
    transform 0.3s var(--ease-out),
    box-shadow 0.3s var(--ease-out),
    background-color 0.2s var(--ease),
    color 0.2s var(--ease),
    opacity 0.2s var(--ease);
}
a.btn {
  display: inline-block;
  text-decoration: none;
}

.btn-primary {
  background: var(--ink);
  color: var(--paper);
  box-shadow: var(--shadow-rest);
}
.btn-primary:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: var(--shadow-lift);
}
/* The press. Quick in, slow out — the release is what feels expensive. */
.btn:active:not(:disabled) {
  transform: translateY(0) scale(0.975);
  box-shadow: var(--shadow-rest);
  transition-duration: var(--dur-press);
}
.btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  box-shadow: none;
}
/* A button that is working (submitting, joining the list) breathes
   rather than sitting dead at 35%. */
@keyframes breathe {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 0.5; }
}
.btn.is-busy:disabled {
  cursor: progress;
  animation: breathe 1.4s var(--ease) infinite;
}

.btn-ghost {
  background: none;
  color: var(--ink-faint);
  padding: 15px 4px;
  border-radius: 4px;
}
.btn-ghost:hover:not(:disabled) { color: var(--ink); }
.btn-ghost:active:not(:disabled) { transform: scale(0.97); }

/* ---- Site chrome ------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--paper-blur);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.35s var(--ease);
}
.site-header.is-scrolled { border-bottom-color: var(--rule); }

.site-header__inner {
  max-width: var(--max);
  margin: 0 auto;
  padding: 18px var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 60px;
}
.site-header__brand {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease-out);
}
.site-header__brand:hover { opacity: 0.65; }
.site-header__brand:active { opacity: 0.5; transform: scale(0.98); transition-duration: var(--dur-press); }

.site-header__nav {
  display: flex;
  gap: 28px;
}
.site-header__nav a {
  position: relative;
  font-size: 15px;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 4px 0;
  transition: color 0.2s var(--ease), opacity 0.2s var(--ease);
}
.site-header__nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease-out), opacity 0.2s var(--ease);
}
.site-header__nav a:hover { color: var(--ink); }
.site-header__nav a:hover::after { transform: scaleX(1); }
.site-header__nav a:active { opacity: 0.55; transition-duration: var(--dur-press); }
/* The page you are on: underlined, quietly, without hover. */
.site-header__nav a[aria-current="page"] { color: var(--ink); }
.site-header__nav a[aria-current="page"]::after {
  transform: scaleX(1);
  opacity: 0.45;
}

/* The audit's header carries the wordmark and a label, no nav. */
.site-header__label {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.site-main {
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(56px, 8vw, 96px) var(--gutter) clamp(72px, 9vw, 112px);
}

/* Sections are separated by air, not by rules — and by exactly one
   amount of air. The last child of a section drops its own bottom
   margin so the section gap is never "gap plus a stray paragraph
   margin". */
.site-section { padding: var(--space-section) 0 0; }
.site-section > :last-child,
.hero > :last-child,
.promo-box > :last-child,
.result-block > :last-child { margin-bottom: 0; }

.hero { padding-bottom: 0; }
.hero h1 {
  font-size: clamp(38px, 5.4vw, 62px);
  line-height: 1.02;
  letter-spacing: -0.03em;
  margin-bottom: 28px;
}
.hero .lede { margin-bottom: 22px; }
.hero .btn { margin-top: 12px; }

/* The primary CTA block: the heaviest thing on the page, but built
   from a soft wash rather than a bordered card. */
.promo-box {
  background: linear-gradient(180deg, var(--paper-raised), var(--paper-dim));
  border: none;
  border-radius: 16px;
  padding: clamp(32px, 4.5vw, 46px);
}
.promo-box h2 { margin-bottom: 16px; }
.promo-box__cta { margin-top: 28px; }

.rule-list {
  list-style: none;
  margin: var(--space-block) 0 0;
  padding: 0;
}
.rule-list li {
  padding: 20px 0;
  border-bottom: 1px solid var(--rule);
}
.rule-list li:first-child { padding-top: 0; }
.rule-list li:last-child { border-bottom: none; padding-bottom: 0; }
.rule-list b {
  font-family: var(--sans);
  font-weight: 600;
}

/* Prose that follows a list resumes at the paragraph rhythm. */
.rule-list + p { margin-top: var(--space-block); }

.newsletter-form {
  display: flex;
  gap: 14px;
  margin-top: 4px;
  flex-wrap: wrap;
  align-items: center;
}
.newsletter-form input[type="email"] {
  flex: 1;
  min-width: min(220px, 100%);
  font-family: var(--sans);
  font-size: 16px;
  color: var(--ink);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--rule-strong);
  padding: 12px 2px;
  outline: none;
  transition: border-color 0.25s var(--ease);
}
.newsletter-form input[type="email"]::placeholder { color: var(--ink-faint); }
.newsletter-form input[type="email"]:focus { border-bottom-color: var(--signal); }

/* Small print that belongs to a form: sits right under it, no rule. */
.form-note {
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink-faint);
  margin: 18px 0 0;
}
.form-note a { color: var(--ink-soft); }
.form-note:empty { display: none; }

/* Inline text links in prose get an underline that thickens on hover. */
.site-main p > a:not(.btn),
.app p > a:not(.btn) {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--rule-strong);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: text-decoration-color 0.25s var(--ease), opacity 0.2s var(--ease);
}
.site-main p > a:not(.btn):hover,
.app p > a:not(.btn):hover { text-decoration-color: var(--signal); }
.site-main p > a:not(.btn):active,
.app p > a:not(.btn):active { opacity: 0.6; transition-duration: var(--dur-press); }

.site-footer {
  border-top: 1px solid var(--rule);
  max-width: var(--max);
  margin: 0 auto;
  padding: 36px var(--gutter) 64px;
  text-align: center;
  color: var(--ink-faint);
  font-size: 14px;
  line-height: 1.9;
}
.site-footer a {
  color: var(--ink-soft);
  text-decoration: none;
  transition: color 0.2s var(--ease), opacity 0.2s var(--ease);
}
.site-footer a:hover { color: var(--ink); }
.site-footer a:active { opacity: 0.55; transition-duration: var(--dur-press); }
.site-footer .sep {
  margin: 0 10px;
  opacity: 0.4;
}
.site-footer nav { margin-bottom: 14px; }
/* A link name never breaks across lines, and the dot between links
   travels with the link that follows it, so a wrapped row never ends
   on a dangling separator. The dot is decorative: hidden from AT. */
.site-footer nav a,
.audit-footer nav a { white-space: nowrap; }
.site-footer nav .sep,
.audit-footer nav .sep { display: none; }
.site-footer nav .sep + a::before,
.audit-footer nav .sep + a::before {
  content: "·" / "";
  color: var(--ink-faint);
  opacity: 0.5;
  margin: 0 10px 0 0;
  padding-left: 10px;
}
.audit-footer nav .sep + a::before { margin-right: 8px; padding-left: 8px; }
/* The address is a different kind of thing from the page links: it gets
   its own line, with no dot. */
.site-footer nav a[href^="mailto:"],
.audit-footer nav a[href^="mailto:"] {
  display: block;
  margin-top: 2px;
}
.site-footer nav a[href^="mailto:"]::before,
.audit-footer nav a[href^="mailto:"]::before { content: none; }
.site-footer__tagline { margin: 0 0 14px; }
.site-footer__operator {
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-faint);
  margin: 0;
  max-width: 46ch;
}

/* ---- Audit app --------------------------------------------- */

.progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: transparent;
  z-index: 30;
}
.progress__fill {
  height: 100%;
  width: 0%;
  background: var(--signal);
  transition: width 0.6s var(--ease-out);
}

.app {
  max-width: var(--max);
  margin: 0 auto;
  padding: clamp(40px, 6vw, 64px) var(--gutter) 96px;
  min-height: 70vh;
}

/* Each step arrives as a short cascade — kicker, title, then the body —
   and leaves as one piece, quickly. The cascade is capped so a long
   screen never crawls in; everything past the sixth child shares a
   delay. */
@keyframes screen-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes screen-out {
  to { opacity: 0; transform: translateY(-6px); }
}
.screen > * {
  animation: screen-in var(--dur-enter) var(--ease-out) backwards;
}
.screen > :nth-child(2) { animation-delay: 40ms; }
.screen > :nth-child(3) { animation-delay: 80ms; }
.screen > :nth-child(4) { animation-delay: 120ms; }
.screen > :nth-child(5) { animation-delay: 160ms; }
.screen > :nth-child(n + 6) { animation-delay: 200ms; }
.screen.is-leaving {
  animation: screen-out var(--dur-leave) var(--ease) forwards;
  pointer-events: none;
}
/* A re-render of the same step (a validation error, a busy state)
   must not replay the entrance. */
.screen--static > * { animation: none; }

.field { margin-bottom: 24px; }
.field label {
  display: block;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 10px;
}
.field input[type="text"],
.field input[type="email"],
.field textarea {
  width: 100%;
  font-family: var(--sans);
  font-size: 17px;
  color: var(--ink);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--rule-strong);
  padding: 11px 2px;
  outline: none;
  transition: border-color 0.25s var(--ease);
}
.field textarea {
  border: 1px solid var(--rule-strong);
  border-radius: 8px;
  padding: 16px;
  min-height: 150px;
  resize: vertical;
  line-height: 1.6;
}
.field input:focus,
.field textarea:focus { border-color: var(--signal); }

.options {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 12px 0 28px;
}
.options-group:last-child .options { margin-bottom: 0; }

.option {
  display: block;
  position: relative;
  width: 100%;
  text-align: left;
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.4;
  color: var(--ink);
  background: var(--paper-dim);
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 16px 18px 16px 50px;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition:
    border-color 0.2s var(--ease),
    background-color 0.2s var(--ease),
    transform 0.25s var(--ease-out);
}
/* The radio itself, drawn by hand so it matches the type. */
.option::before {
  content: "";
  position: absolute;
  left: 18px;
  top: 50%;
  width: 16px;
  height: 16px;
  margin-top: -8px;
  border-radius: 50%;
  border: 1px solid var(--rule-strong);
  background: var(--paper);
  box-shadow: inset 0 0 0 0 var(--signal);
  transition:
    box-shadow 0.22s var(--ease-out),
    border-color 0.2s var(--ease),
    transform 0.25s var(--ease-out);
}
.option:hover {
  border-color: var(--rule-strong);
  transform: translateX(2px);
}
.option:active {
  transform: translateX(2px) scale(0.99);
  transition-duration: var(--dur-press);
}
.option:active::before { transform: scale(0.85); }
.option input[type="radio"] {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  pointer-events: none;
}
/* Selection and focus follow the input's real state, so what is
   painted and what is announced can never disagree. */
.option.selected,
.option:has(input[type="radio"]:checked) {
  border-color: var(--signal);
  background: var(--signal-soft);
  transform: none;
}
.option.selected::before,
.option:has(input[type="radio"]:checked)::before {
  border-color: var(--signal);
  box-shadow: inset 0 0 0 5px var(--signal);
}
.option:has(input[type="radio"]:focus-visible) {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
}
.option .code {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-faint);
  margin-right: 10px;
}
.option-note {
  font-family: var(--serif);
  font-style: italic;
  font-size: 14px;
  color: var(--ink-faint);
  margin: 10px 0 0;
}
.options-group:has(.option-note) .options { margin-bottom: 0; }
.options-group:has(.option-note):not(:last-child) .option-note { margin-bottom: 28px; }

.options-group {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.options-group > legend {
  padding: 0;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(21px, 1.1vw + 18px, 25px);
  line-height: 1.3;
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--ink);
}

.actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 40px;
}
.actions__group {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.actions--flush { margin-top: 0; }
.actions + .disabled-reason { text-align: right; }

.meta-row {
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-faint);
  margin-bottom: 28px;
}

.footnote {
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink-faint);
  margin-top: 40px;
  padding-top: 20px;
  border-top: 1px solid var(--rule);
}
.footnote a { color: var(--ink-soft); }
.footnote:empty { display: none; }

.result-number {
  display: block;
  font-family: var(--serif);
  font-size: clamp(52px, 12vw, 84px);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -0.035em;
  margin: 4px 0 0;
}
.result-band {
  color: var(--ink-soft);
  margin-bottom: 40px;
}

.result-block {
  padding: 32px 0;
  border-top: 1px solid var(--rule);
}
.result-block:last-of-type { border-bottom: 1px solid var(--rule); }
.result-block .kicker { margin-bottom: 12px; }
.result-block h2 { margin-bottom: 14px; }
.result-block p { white-space: pre-line; }
.result-block .actions { margin: 4px 0 28px; }
/* The closing line after the result blocks: one rule, not two. */
.result-block + .footnote {
  border-top: none;
  padding-top: 0;
  margin-top: 28px;
}

/* A run of fields gets a little more air than a paragraph would. */
.fields { margin-top: 32px; }

.center-note {
  text-align: center;
  color: var(--ink-faint);
  padding: 60px 0;
}

/* ---- Narrow screens ---------------------------------------- */

@media (max-width: 600px) {
  :root { --gutter: 20px; }
  .site-header__inner { padding: 14px var(--gutter); min-height: 54px; }
  .site-header__nav { gap: 20px; }
  .site-header__label { display: none; }
  .site-main { padding: 48px var(--gutter) 80px; }
  .site-footer { padding: 32px var(--gutter) 56px; }
  .site-footer .sep { margin: 0 8px; }
  .app { padding: 36px var(--gutter) 80px; }
  .btn { padding: 14px 22px; }
  .actions { margin-top: 32px; }
  .option { padding: 15px 16px 15px 46px; }
  .option::before { left: 16px; }
  .rule-list li { padding: 18px 0; }
}

/* ---- Reduced motion ---------------------------------------- */
/* Everything above that moves stops here. Kept last so nothing
   later in the file can reintroduce it by accident. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js-reveal [data-reveal],
  .js-reveal [data-reveal].is-visible {
    opacity: 1;
    transform: none;
    transition: none;
  }
  html.is-leaving body > main,
  html.is-leaving body > footer {
    opacity: 1;
    transform: none;
  }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
  }
}


/* ============================================================
   Accessibility primitives
   Added in the WCAG 2.2 AA pass. Nothing here changes the look
   of the site for a mouse user; all of it changes what a
   keyboard or screen-reader user can do.
   ============================================================ */

/* Visible only to screen readers. Used for the live region that
   announces validation errors and step changes. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* First tab stop on every page. Off-screen until focused. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--paper);
  color: var(--ink);
  padding: 12px 18px;
  border: 1px solid var(--signal);
  border-radius: 0 0 6px 0;
  font-size: 15px;
  text-decoration: none;
}
.skip-link:focus {
  left: 0;
}

/* ---- Explaining a disabled control ------------------------
   A Next button that is disabled until the screen is complete
   has to say so, rather than leaving someone pressing Tab and
   guessing. */
.field-hint,
.disabled-reason {
  font-size: 14px;
  color: var(--ink-faint);
  margin: 10px 0 0;
}
.field-hint {
  font-size: 13px;
  margin: -4px 0 8px;
}

/* ---- Validation errors ------------------------------------ */
.error-text {
  color: var(--signal);
  font-size: 15px;
  margin: 12px 0 20px;
}
.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-color: var(--signal);
}

/* ---- Consent checkbox -------------------------------------
   Its own label, its own decision, never pre-ticked. */
.consent {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 20px 0 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-soft);
  cursor: pointer;
}
.consent input[type="checkbox"] {
  flex: none;
  width: 18px;
  height: 18px;
  margin: 3px 0 0;
  accent-color: var(--signal);
  cursor: pointer;
}

/* The audit gets the same footer, held below the flow rather
   than pinned, so it never competes with the current screen. */
.audit-footer {
  max-width: var(--max);
  margin: 0 auto;
  padding: 28px var(--gutter) 56px;
  border-top: 1px solid var(--rule);
  font-size: 14px;
  line-height: 1.9;
  color: var(--ink-faint);
  text-align: center;
}
.audit-footer a {
  color: var(--ink-soft);
  text-decoration: none;
  transition: color 0.2s var(--ease), opacity 0.2s var(--ease);
}
.audit-footer a:hover { color: var(--ink); }
.audit-footer a:active { opacity: 0.55; transition-duration: var(--dur-press); }
.audit-footer .sep { margin: 0 8px; opacity: 0.5; }
.audit-footer__operator {
  font-size: 13px;
  margin: 12px 0 0;
  max-width: 46ch;
}

/* ---- Turnstile --------------------------------------------
   The widget renders an iframe of its own. In interaction-only
   mode it is invisible unless a challenge is needed, so it must
   not reserve height: an empty 65px hole between a form and its
   small print is exactly the kind of gap this site does not have. */
.turnstile {
  margin: 0;
  min-height: 0;
}
.turnstile iframe { display: block; }


/* ============================================================
   The Redesign — the paid workbook at /redesign/app.
   Same tokens, same type, same components as the audit. What is
   new here is only what the audit never needed: a removable line,
   a list you can reorder, a small card, a page you can print.
   ============================================================ */

/* The session label in the header stays visible on a phone here:
   "Session 2 of 5" is the only place progress is written down. */
.redesign .site-header__label { display: inline; }

/* Two-tone paragraph: the audit's own words, quoted back. */
.rd-quote {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(19px, 1.6vw, 22px);
  line-height: 1.4;
  margin: 0 0 var(--space-para);
}

/* A run of bucket items. Plain lines, hairline-separated. */
.rd-list {
  list-style: none;
  margin: 0 0 var(--space-block);
  padding: 0;
}
.rd-list li {
  padding: 12px 0;
  border-bottom: 1px solid var(--rule);
}
.rd-list li:last-child { border-bottom: none; }
.rd-list .rd-empty {
  font-style: italic;
  color: var(--ink-soft);
}
.rd-sub {
  display: block;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-faint);
  margin-top: 4px;
}

/* A block that belongs together — one item on the map, one
   candidate in the three tests. The audit's result-block, reused. */
.rd-block {
  padding: 24px 0;
  border-top: 1px solid var(--rule);
}
.rd-block:last-of-type { border-bottom: 1px solid var(--rule); }
.rd-block > .kicker { margin-bottom: 10px; }
.rd-block > h2 { margin-bottom: 12px; }
.rd-block > :last-child { margin-bottom: 0; }
.rd-block .options { margin-bottom: 20px; }
.rd-block .options-group:last-child .options { margin-bottom: 0; }

/* Editable line: an input with a small remove control beside it. */
.rd-line {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.rd-line .field { flex: 1; margin: 0; }
.rd-line .btn-ghost { padding: 10px 6px; font-size: 14px; }

/* Ordered list with up/down controls. Drag is unreliable on a phone;
   two buttons are not. */
.rd-seq {
  list-style: none;
  margin: 0 0 var(--space-block);
  padding: 0;
  counter-reset: seq;
}
.rd-seq li {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid var(--rule);
}
.rd-seq li:last-child { border-bottom: none; }
.rd-seq li::before {
  counter-increment: seq;
  content: counter(seq);
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-faint);
  min-width: 18px;
  padding-top: 4px;
}
.rd-seq .rd-seq__body { flex: 1; min-width: 0; }
.rd-seq .rd-seq__kind {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 4px;
}
.rd-seq .rd-seq__ctl {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.rd-seq .rd-seq__ctl .btn-ghost {
  padding: 4px 8px;
  font-size: 15px;
  line-height: 1;
}
.rd-seq .rd-seq__ctl .btn-ghost:disabled { opacity: 0.25; }

/* Number and date inputs share the text input's look. */
.field input[type="number"],
.field input[type="date"] {
  width: 100%;
  font-family: var(--sans);
  font-size: 17px;
  color: var(--ink);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--rule-strong);
  padding: 11px 2px;
  outline: none;
  transition: border-color 0.25s var(--ease);
}
.field input[type="number"]:focus,
.field input[type="date"]:focus { border-color: var(--signal); }
.field input[type="number"] { max-width: 160px; }
.field input[type="date"] { max-width: 220px; }

/* Small print that is neither an error nor a hint: a warning that
   doesn't block. */
.rd-warn {
  font-size: 14px;
  color: var(--signal);
  margin: 8px 0 0;
}
.rd-warn:empty { display: none; }

/* "Save and come back later", under the actions on every screen. */
.rd-later {
  text-align: center;
  font-size: 14px;
  color: var(--ink-faint);
  margin: 28px 0 0;
}
.rd-later a { color: var(--ink-soft); }
.rd-status {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
  min-height: 1.2em;
  margin: 6px 0 0;
  text-align: right;
}

/* ---- The Personal Policy page (5.2) ------------------------ */
/* The product's one visual moment. It should look like something
   worth printing: ink on paper, generous margins, no decoration. */
.policy {
  background: var(--paper-raised);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: clamp(28px, 6vw, 56px) clamp(22px, 6vw, 56px);
  margin: 0 0 32px;
  color: var(--ink);
}
.policy h2 {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin: 0 0 6px;
}
.policy__title {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(26px, 4vw, 34px);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0 0 4px;
}
.policy__date {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
  margin: 0 0 32px;
}
.policy section { margin: 0 0 26px; }
.policy h3 {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 8px;
}
.policy ul { list-style: none; margin: 0; padding: 0; }
.policy li { margin: 0 0 6px; padding-left: 16px; text-indent: -16px; }
.policy li::before { content: "– "; color: var(--ink-faint); }
.policy p { margin: 0 0 6px; font-size: 16px; line-height: 1.55; }
.policy .policy__label {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  margin-right: 6px;
}
/* Every line is editable in place. It must not look like a form:
   no box until it is focused, and then only a hairline. */
.policy [contenteditable] {
  display: inline;
  min-width: 2ch;
  outline: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s var(--ease);
}
.policy [contenteditable]:hover { border-bottom-color: var(--rule-strong); }
.policy [contenteditable]:focus { border-bottom-color: var(--signal); }
.policy [contenteditable]:empty::before {
  content: attr(data-empty);
  color: var(--ink-faint);
  font-style: italic;
}
.policy .policy__signed {
  margin-top: 36px;
  font-family: var(--serif);
  font-style: italic;
  color: var(--ink-soft);
}
.policy .policy__signed span {
  display: inline-block;
  min-width: 180px;
  border-bottom: 1px solid var(--rule-strong);
  margin-left: 8px;
}
.policy__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 8px;
  align-items: center;
  margin: 0 0 8px;
}
.policy__confirmed {
  font-size: 15px;
  color: var(--ink-soft);
  margin: 12px 0 0;
}
.policy__confirmed:empty { display: none; }

@media (max-width: 600px) {
  .policy { padding: 26px 20px; }
  .policy__actions .btn { flex: 1 1 100%; text-align: center; }
}

/* ---- Print: one clean page ---------------------------------- */
/* Only the Policy itself prints. @page margin 0 is what removes the
   browser's own URL and date header; the sheet carries its margins
   inside instead. Backgrounds are forced so the paper colour survives. */
@media print {
  @page { margin: 0; }
  html, body { background: var(--paper) !important; }
  body::before,
  .progress, .site-header, .audit-footer, .skip-link,
  .redesign .screen > :not(.policy),
  .policy__actions, .policy__confirmed, .rd-later, .rd-status { display: none !important; }
  .app { padding: 0; margin: 0; max-width: none; min-height: 0; }
  .screen > * { animation: none !important; }
  .policy {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
    background: var(--paper) !important;
    color: var(--ink) !important;
    border: none;
    border-radius: 0;
    margin: 0;
    padding: 18mm 20mm;
    min-height: 100vh;
    box-sizing: border-box;
    page-break-inside: avoid;
    font-size: 10.5pt;
  }
  .policy p { font-size: 10.5pt; line-height: 1.4; }
  .policy li { margin-bottom: 3pt; }
  .policy section { margin-bottom: 16pt; }
  .policy__date { margin-bottom: 20pt; }
  .policy [contenteditable] { border-bottom: none !important; }
  .policy [contenteditable]:empty::before { content: ""; }
}

/* Inside a card (the three tests), a question is a label, not a title. */
.rd-block .options-group > legend {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0;
  margin: 8px 0 0;
}

/* A hint that sits between a box and the next question keeps the
   paragraph rhythm below it. */
.screen > .option-note { margin-bottom: var(--space-para); }
