/* ==========================================================================
   Arkvento design system
   Built from /assets/brand/BRAND.md and /site/DESIGN.md.
   One stylesheet for every page. No framework. No inline styles.
   Order: fonts, tokens, reset, base, layout, type, then components.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Fonts. Four faces, 47KB, self-hosted, subset to the characters the site
   uses. Sora is variable across 500 and 700 from one file.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Sora";
  src: url("../fonts/sora.woff2") format("woff2-variations"),
       url("../fonts/sora.woff2") format("woff2");
  font-weight: 500 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("../fonts/source-serif-4.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("../fonts/source-serif-4-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../fonts/jetbrains-mono.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* Metric-matched fallbacks, so the swap from fallback to webfont does not move
   the layout. size-adjust is the measured ratio of a test string set in the real
   face against the real fallback; the ascent and descent overrides are each
   face's own hhea values divided by that ratio. Measured, not estimated. */
@font-face {
  font-family: "Sora Fallback";
  src: local("Helvetica Neue"), local("Helvetica"), local("Arial"), local("Liberation Sans");
  size-adjust: 114.2%;
  ascent-override: 85.0%;
  descent-override: 25.4%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Serif Fallback";
  src: local("Georgia"), local("Times New Roman"), local("Liberation Serif");
  font-style: normal;
  size-adjust: 102.0%;
  ascent-override: 101.6%;
  descent-override: 32.8%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Serif Fallback";
  src: local("Georgia Italic"), local("Georgia"), local("Times New Roman Italic");
  font-style: italic;
  size-adjust: 93.6%;
  ascent-override: 110.7%;
  descent-override: 35.8%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Mono Fallback";
  src: local("SF Mono"), local("Menlo"), local("Consolas"), local("DejaVu Sans Mono");
  size-adjust: 99.7%;
  ascent-override: 102.3%;
  descent-override: 30.1%;
  line-gap-override: 0%;
}

/* --------------------------------------------------------------------------
   2. Tokens. Every value the site is allowed to use.
   -------------------------------------------------------------------------- */

:root {
  /* Grounds and surfaces */
  --ground: #07090F;
  --paper: #F2F3F7;
  --surface: #FFFFFF;

  /* Ink */
  --ink: #1B1A2E;
  --ink-2: #4A4960;
  --ink-3: #7B7A90;          /* rules, placeholders, disabled. Never text under 24px */
  --line: #DCDDE6;

  /* On dark grounds */
  --on-dark: #F2F3F7;
  --on-dark-2: rgba(242, 243, 247, 0.72);
  --on-dark-3: rgba(242, 243, 247, 0.52);
  --line-dark: rgba(242, 243, 247, 0.14);

  /* Accent. Drawn from the mark rather than from the usual indigo: the wave in
     the logo is hue 213 and this is hue 216, so it reads as the same blue. The
     wave's own #2E77DC cannot be used directly, because it reaches only 4.4 on
     white and 4.0 on paper. This is that blue taken deep enough to pass.
     Named for the job rather than the hue, so the name cannot go stale. */
  --accent: #1C59B5;        /* 6.68 on white, 6.02 on paper, 6.68 for white on it */
  --accent-deep: #174C99;   /* hover */
  --accent-press: #123D7C;  /* active */
  --accent-soft: #E3EDFB;   /* wash */
  --accent-tint: #8FBEFF;   /* links and focus rings on dark: 10.4 on the ground */

  /* Status. --bad draws the error borders and fills; the -text variants are for
     small text, and reach 4.5:1 on white where the brand's #2E8B6A and #D97A2B
     do not. Those two are in BRAND.md as fills and nothing on the site fills
     with them, so they are not carried here. */
  --bad: #B3261E;
  --good-text: #1F6B50;
  --warn-text: #A8551A;
  --bad-text: #B3261E;

  /* Type */
  --sans: "Sora", "Sora Fallback", system-ui, sans-serif;
  --serif: "Source Serif 4", "Serif Fallback", Georgia, serif;
  --mono: "JetBrains Mono", "Mono Fallback", ui-monospace, SFMono-Regular, Menlo, monospace;

  --size-display: clamp(2.125rem, 1.35rem + 3.4vw, 3.5rem);   /* 34 to 56 */
  --size-h2: clamp(1.625rem, 1.35rem + 1.2vw, 2.125rem);      /* 26 to 34 */
  --size-h3: 1.25rem;                                         /* 20 */
  --size-lead: clamp(1.125rem, 1.05rem + 0.35vw, 1.25rem);    /* 18 to 20 */
  --size-body: 1.0625rem;                                     /* 17 */
  --size-small: 0.9375rem;                                    /* 15 */
  --size-meta: 0.84375rem;                                    /* 13.5 */
  --size-label: 0.8125rem;                                    /* 13 */
  --size-figure: 2.125rem;                                    /* 34 */

  --leading-body: 1.75rem;                                    /* 28px, on the 4px grid */

  /* Measure */
  --measure: 68ch;
  --measure-lead: 56ch;
  --measure-tight: 20ch;
  --measure-h2: 26ch;
  --measure-bullet: 42ch;

  /* Space, a 4px scale */
  --s1: 0.25rem;  --s2: 0.5rem;   --s3: 0.75rem;  --s4: 1rem;
  --s5: 1.5rem;   --s6: 2rem;     --s7: 2.5rem;   --s8: 3rem;
  --s9: 4rem;     --s10: 5rem;    --s11: 6rem;    --s12: 8rem;

  --section-y: clamp(4.5rem, 8vw, 7rem);        /* 72 to 112 */
  --section-y-dark: clamp(4rem, 7vw, 6rem);     /* 64 to 96 */

  /* Frame */
  --container: 1100px;
  --gutter: 1.5rem;
  --radius: 4px;
  --hairline: 1px;
  --header-h: 64px;

  --speed: 150ms;
  --ease: ease;

  /* Context switches. Any dark container sets these once and every component
     inside it follows, so a new dark section can never be forgotten. */
  --focus-ring: var(--accent);
  --btn-primary-border: transparent;
}

/* The dark contexts. One list, used everywhere below via :is(). */
.section--dark, .hero, .site-footer {
  --focus-ring: var(--accent-tint);
  --btn-primary-border: var(--accent-tint);
}

@media (max-width: 479px)  { :root { --gutter: 1.25rem; --header-h: 56px; } }
@media (min-width: 1180px) { :root { --gutter: 2rem; } }

/* --------------------------------------------------------------------------
   3. Reset. Only what is needed.
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--s5));
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: 0ms !important; animation-duration: 0ms !important; }
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--size-body);
  line-height: var(--leading-body);
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;      /* insurance only. Nothing should ever overflow */
}

::selection { background: var(--accent-soft); color: var(--ink); }
:is(.section--dark, .hero, .site-footer) ::selection { background: var(--accent); color: #fff; }

img, svg, video { display: block; max-width: 100%; height: auto; }
input, button, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; }
ul, ol { list-style: none; padding: 0; }

/* --------------------------------------------------------------------------
   4. Base typography
   -------------------------------------------------------------------------- */

h1, h2, h3, h4 {
  font-family: var(--sans);
  font-weight: 700;
  color: var(--ink);
  text-wrap: balance;
}
h1 { font-size: var(--size-display); line-height: 1.05; letter-spacing: -0.02em;
     max-width: var(--measure-tight); font-family: var(--sans); font-weight: 700;
     text-wrap: balance; color: var(--ink); }
h2 { font-size: var(--size-h2);      line-height: 1.15; letter-spacing: -0.015em; max-width: var(--measure-h2); }
h3 { font-size: var(--size-h3);      line-height: 1.25; letter-spacing: -0.01em; }

p, li { max-width: var(--measure); text-wrap: pretty; }
p + p { margin-top: var(--s5); }

strong, b { font-weight: 600; }
em, i { font-style: italic; }

/* Section label. The small uppercase line that opens a section, taken from
   the report's own headings. Always sits under a hairline. */
.label {
  font-family: var(--sans);
  font-weight: 700;
  font-size: var(--size-label);
  line-height: 1.2;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
  border-top: var(--hairline) solid var(--line);
  padding-top: var(--s3);
  margin-bottom: var(--s3);
  max-width: none;
}
/* Inside a section head the rule belongs to the head, so that a section which
   needs no kicker still opens on the same line as one that does. */
.section-head { border-top: var(--hairline) solid var(--line); padding-top: var(--s3); }
.section-head > .label { border-top: 0; padding-top: 0; }
.lead   { font-size: var(--size-lead); line-height: 1.5; max-width: var(--measure-lead); color: var(--ink); }
.small  { font-size: var(--size-small); line-height: 1.55; }
.meta   { font-family: var(--sans); font-weight: 500; font-size: var(--size-meta);
          line-height: 1.45; letter-spacing: 0.01em; color: var(--ink-2); max-width: 60ch; }
.figure { font-family: var(--mono); font-weight: 500; font-size: var(--size-figure);
          line-height: 1; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; color: var(--ink); }

/* Prose lists. A 6px accent rule instead of a bullet or an icon. */
.list > li { position: relative; padding-left: var(--s5); max-width: var(--measure-bullet); }
.list > li + li { margin-top: var(--s3); }
.list > li::before {
  content: ""; position: absolute; left: 0; top: 0.72em;
  width: 6px; height: 1px; background: var(--accent);
}

/* --------------------------------------------------------------------------
   5. Layout
   -------------------------------------------------------------------------- */

.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }

.section { padding-block: var(--section-y); }
.section--paper   { background: var(--paper); }
.section--surface { background: var(--surface); }
.section--dark    { background: var(--ground); padding-block: var(--section-y-dark); }

/* Content on a dark ground. The hero and the footer are dark grounds too, so
   they are in the same list rather than repeating the rules. */
:is(.section--dark, .hero) :is(h1, h2, h3) { color: var(--on-dark); }
:is(.section--dark, .hero) :is(p, li, .lead) { color: var(--on-dark-2); }
:is(.section--dark, .hero, .site-footer) .label { color: var(--on-dark-2); border-top-color: var(--line-dark); }
:is(.section--dark, .hero) .section-head { border-top-color: var(--line-dark); }
:is(.section--dark, .hero) .meta { color: var(--on-dark-3); }
:is(.section--dark, .hero) .figure { color: var(--on-dark); }
:is(.section--dark, .hero, .site-footer) a:not(.btn) { color: var(--accent-tint); }
:is(.section--dark, .hero, .site-footer) .list > li::before { background: var(--accent-tint); }
:is(.section--dark, .hero) hr,
:is(.section--dark, .hero) .card { border-color: var(--line-dark); }


/* Two blocks in one section, separated by space rather than by a second
   section's padding, so the ground rhythm stays as designed. */
.block-gap { margin-top: clamp(3.5rem, 6vw, 5rem); }
.block-gap-sm { margin-top: var(--s7); }

/* A run of paragraphs. The measure is already on p, this only sets the rhythm. */
.prose > * + * { margin-top: var(--s5); }

.section-head { margin-bottom: var(--s7); }
.section-head > h2 + .lead { margin-top: var(--s5); }

/* Wide viewports: the heading and its deck sit side by side rather than stacked,
   so the section uses its full measure and the page gains a second alignment
   axis. Below 1000px they stack, which is the natural order anyway. */
@media (min-width: 1000px) {
  .section-head:has(> .lead) {
    display: grid;
    grid-template-columns: 5fr 6fr;
    column-gap: var(--s8);
    align-items: start;
  }
  .section-head > .label { grid-column: 1 / -1; }
  .section-head > h2 { grid-column: 1; margin-bottom: 0; }
  .section-head > h2 + .lead { grid-column: 2; margin-top: 0.35rem; max-width: none; }
}

/* --------------------------------------------------------------------------
   6. Links, skip link, focus
   -------------------------------------------------------------------------- */

a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.14em;
  transition: color var(--speed) var(--ease), text-decoration-thickness var(--speed) var(--ease);
}
@media (hover: hover) {
  a:hover { color: var(--ink); text-decoration-thickness: 2px; }
  :is(.section--dark, .hero, .site-footer) a:not(.btn):hover { color: var(--on-dark); }
}

:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: 2px;
}

.skip {
  position: absolute; left: var(--s4); top: var(--s4);
  transform: translateY(-200%);
  z-index: 100;
  background: var(--accent); color: #fff;
  font-family: var(--sans); font-weight: 700; font-size: var(--size-small);
  padding: var(--s3) var(--s4); border-radius: var(--radius);
  text-decoration: none;
}
.skip:focus { transform: none; }

/* --------------------------------------------------------------------------
   7. Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0.875rem 1.5rem;
  font-family: var(--sans); font-weight: 700; font-size: 1rem; line-height: 1.2;
  border-radius: var(--radius);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--speed) var(--ease), border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}
.btn--primary { background: var(--accent); color: #fff; border: 1px solid var(--btn-primary-border); }
.btn--secondary { background: transparent; color: var(--ink); border: 1px solid var(--ink); }

@media (hover: hover) {
  .btn--primary:hover { background: var(--accent-deep); color: #fff; }
  .btn--secondary:hover { background: rgba(27, 26, 46, 0.05); color: var(--ink); }
}
.btn--primary:active { background: var(--accent-press); }

/* On a dark ground the accent fill sits at only 3.0:1 against the ground, at the
   very edge of what a control boundary needs, so --btn-primary-border gives it a
   hairline there. That is the only reason a button ever has a visible border. */
:is(.section--dark, .hero) .btn--secondary {
  color: var(--on-dark); border-color: rgba(242, 243, 247, 0.28); background: transparent;
}
@media (hover: hover) {
  :is(.section--dark, .hero) .btn--secondary:hover {
    background: rgba(242, 243, 247, 0.08); color: var(--on-dark);
  }
}

/* A text call to action. Not a button, and never dressed as one, but still a
   standalone target, so it carries a full 44px tap height. */
.link-cta {
  display: inline-flex; align-items: center; min-height: 44px;
  font-family: var(--sans); font-weight: 500; font-size: 1rem;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.16em;
}

.actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s5); }
@media (max-width: 639px) {
  .actions { gap: var(--s4); }
  .actions .btn,
  .price-action .btn,
  .two-col .btn { width: 100%; }
}

/* --------------------------------------------------------------------------
   8. Header and navigation
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky; top: 0; z-index: 50;
  height: var(--header-h);
  display: flex; align-items: center;
}
.site-header--light { background: var(--surface); border-bottom: var(--hairline) solid var(--line); }

.site-header .container { display: flex; align-items: center; justify-content: space-between; gap: var(--s5); }

.brand { display: inline-flex; align-items: center; gap: 0.75rem; min-height: 44px; text-decoration: none; }
.brand img { height: 28px; width: auto; }
.brand-name {
  font-family: var(--sans); font-weight: 700; font-size: 1.125rem;
  letter-spacing: -0.01em; line-height: 1;
}
.site-header--light .brand-name { color: var(--ink); }

.nav ul { display: flex; align-items: center; gap: var(--s6); }
.nav a {
  font-family: var(--sans); font-weight: 500; font-size: var(--size-small);
  text-decoration: none;
  display: inline-flex; align-items: center; min-height: 44px;
}
.site-header--light .nav a { color: var(--ink-2); }
@media (hover: hover) {
  .site-header--light .nav a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 0.4em; }
}
.nav a[aria-current="page"] {
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.4em;
}

/* The contact line belongs to the mobile panel only. */
.nav-contact { display: none; }
.site-header--light .nav a[aria-current="page"] { color: var(--ink); text-decoration-color: var(--accent); }

/* The control is labelled with a word, not a glyph. */
.nav-toggle {
  display: none;
  font-family: var(--sans); font-weight: 500; font-size: var(--size-small);
  min-height: 44px; padding-inline: var(--s2);
  cursor: pointer;
}
.site-header--light .nav-toggle { color: var(--ink); }

@media (max-width: 719px) {
  /* :not([hidden]) matters. The control ships hidden and the script reveals it,
     so that with no JavaScript there is no button that does nothing. Without the
     guard this display would win over the hidden attribute. */
  .nav-toggle:not([hidden]) { display: inline-flex; align-items: center; }
  .nav {
    position: absolute; left: 0; right: 0; top: var(--header-h);
    border-bottom: var(--hairline) solid var(--line-dark);
    /* The header is sticky, so the panel cannot be scrolled into view by
       scrolling the page. On a landscape phone it was taller than the screen and
       its last rows were unreachable. It scrolls within itself instead. */
    max-height: calc(100vh - var(--header-h));
    max-height: calc(100dvh - var(--header-h));
    overflow-y: auto;
  }
  .site-header--light .nav { background: var(--surface); border-bottom-color: var(--line); }
  .nav[hidden] { display: none; }
  .nav ul { display: block; }
  .nav li + li { border-top: var(--hairline) solid var(--line-dark); }
  .site-header--light .nav li + li { border-top-color: var(--line); }
  /* Scoped to the list, so the contact line below it stays a sentence. */
  .nav ul a {
    display: flex; align-items: center;
    min-height: 56px; font-size: 1.25rem;
    padding-inline: var(--gutter);
    max-width: none;
  }
  .nav-contact a { color: inherit; text-decoration: underline; text-underline-offset: 0.16em; }
  .nav .nav-contact {
    display: block;
    border-top: var(--hairline) solid var(--line-dark);
    padding: var(--s4) var(--gutter);
    max-width: none;
  }
  .site-header--light .nav .nav-contact { border-top-color: var(--line); }
}

/* --------------------------------------------------------------------------
   9. Footer
   -------------------------------------------------------------------------- */

.site-footer { background: var(--ground); color: var(--on-dark-2); padding-block: var(--s9) var(--s7); }
.site-footer h2 { font-size: var(--size-label); letter-spacing: 0.14em; text-transform: uppercase;
                  color: var(--on-dark-3); margin-bottom: var(--s4); max-width: none; }
.site-footer a { color: var(--on-dark-2); text-decoration: none; }
@media (hover: hover) { .site-footer a:hover { color: var(--on-dark); text-decoration: underline; } }
.site-footer .brand-name { color: var(--on-dark); }
/* .meta and .small default to ink, which is unreadable on the ground. */
.site-footer .meta, .site-footer .small, .site-footer p { color: var(--on-dark-2); }

.footer-zones { display: grid; gap: var(--s7); }
.footer-zones > * { min-width: 0; }
.footer-list li { font-size: var(--size-small); max-width: none; }
.footer-list a { display: inline-flex; align-items: center; min-height: 40px;
                 overflow-wrap: anywhere; }
/* Rows that are not links keep the same rhythm. */
.footer-list li:not(:has(a)) { display: flex; align-items: center; min-height: 40px; padding-block: var(--s2); }
.footer-legal {
  margin-top: var(--s7); padding-top: var(--s5);
  border-top: var(--hairline) solid var(--line-dark);
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s3) var(--s6);
}
.site-footer .footer-legal p { color: var(--on-dark-3); font-family: var(--sans); font-weight: 500;
                  font-size: var(--size-meta); max-width: 60ch; }

@media (min-width: 720px) {
  .footer-zones { grid-template-columns: 5fr 3fr 4fr; gap: var(--gutter); }
}

/* --------------------------------------------------------------------------
   10. Forms
   -------------------------------------------------------------------------- */

.form { max-width: 560px; }

.field { display: block; margin-bottom: var(--s5); }
.field > .field-label {
  display: flex; align-items: baseline; gap: var(--s2);
  font-family: var(--sans); font-weight: 500; font-size: 0.875rem;
  color: var(--ink); margin-bottom: 0.375rem;
}
.field-note { font-family: var(--sans); font-weight: 500; font-size: var(--size-meta); color: var(--ink-2); }
.field-help { display: block; margin-top: 0.375rem; font-size: var(--size-small); color: var(--ink-2); max-width: 480px; }

.input, .select {
  width: 100%; max-width: 480px; min-height: 48px;
  padding: 0.8125rem 0.875rem;
  font-family: var(--sans); font-weight: 500; font-size: var(--size-body);
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color var(--speed) var(--ease);
}
.input::placeholder { color: var(--ink-3); }
.input:hover, .select:hover { border-color: var(--ink-3); }
.input:focus-visible, .select:focus-visible { border-color: var(--accent); }

.select {
  appearance: none;
  padding-right: 2.5rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-2) 50%),
                    linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position: calc(100% - 1.15rem) 1.35rem, calc(100% - 0.85rem) 1.35rem;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

/* Consent. A 44px row, never pre-ticked. */
.check { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--s3);
          min-height: 44px; padding-block: var(--s2); }
.check .field-error { flex-basis: 100%; margin-left: calc(24px + var(--s3)); margin-top: 0; }
/* 24px, the WCAG 2.2 minimum target size. The label is clickable as well. */
.check input { width: 24px; height: 24px; margin-top: 0.16rem; accent-color: var(--accent); flex: none; }
.check label { font-size: var(--size-small); max-width: 60ch; }

.form-note { margin-top: var(--s4); font-family: var(--sans); font-weight: 500;
             font-size: var(--size-meta); color: var(--ink-2); max-width: 56ch; }

/* Honeypot. Off screen rather than display:none, so Netlify still sees it. */
.hp { position: absolute; left: -9999px; opacity: 0; height: 0; overflow: hidden; }

/* Errors. The border changes width as well as colour, so the error is never
   signalled by colour alone. */
.field.is-error .input,
.field.is-error .select { border: 2px solid var(--bad); }
.field-error {
  display: none;
  margin-top: 0.375rem;
  font-family: var(--sans); font-weight: 500; font-size: var(--size-small);
  color: var(--bad-text); max-width: 480px;
}
.field.is-error .field-error,
.check.is-error .field-error { display: block; }
/* A checkbox takes no border, so its error state is drawn around the control. */
.check.is-error input { outline: 2px solid var(--bad); outline-offset: 2px; }

.form-summary {
  display: none;
  margin-bottom: var(--s5); padding: var(--s4) var(--s5);
  border-left: 3px solid var(--bad); background: var(--surface);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.form-summary.is-visible { display: block; }
.form-summary h2 { font-size: var(--size-h3); color: var(--bad-text); margin-bottom: var(--s3); max-width: none; }
.form-summary a { color: var(--bad-text); }
.form-summary .list > li::before { background: var(--bad); }
.form-summary .list > li { max-width: none; }

/* --------------------------------------------------------------------------
   11. Cards. Two types on the whole site and no third.
   -------------------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  padding: var(--s5);
}
@media (min-width: 720px) { .card { padding: var(--s6); } }
/* Cards do not respond to hover. They are not links. */

/* 11a. Question tile. Page one of the report, restated. */
.qtiles { display: grid; gap: var(--s4); }
@media (min-width: 720px) { .qtiles { grid-template-columns: repeat(3, 1fr); } }

.qtile {
  background: var(--surface);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  padding: var(--s5);
  display: flex; flex-direction: column; gap: var(--s3);
}
.qtile .q { font-style: italic; color: var(--ink); max-width: none; }
.qtile .q .var { font-family: var(--mono); font-style: normal; font-size: 0.9em; color: var(--accent); }
.qtile .note { font-family: var(--sans); font-weight: 500; font-size: var(--size-meta);
               color: var(--ink-2); max-width: none; margin-top: auto; }
/* The sentence that teaches the outcome vocabulary, directly under the row. */
.qtiles-note { margin-top: var(--s5); }

/* The three outcome words, named in running text where they are true. */
.outcome { font-family: var(--sans); font-weight: 700; font-size: 0.85em;
           letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; }
.outcome--good { color: var(--good-text); }
.outcome--warn { color: var(--warn-text); }
.outcome--bad  { color: var(--bad-text); }

/* The guarantee. A quotation, so it is marked as one, but set as plain text:
   no quotation marks, no rule, no box. Its weight comes from the dark band. */
.pledge { margin-top: var(--s6); }
.pledge-note { margin-top: var(--s5); max-width: 58ch;
               font-family: var(--sans); font-weight: 500; font-size: var(--size-meta); }
/* The brightest text in the band, because it is the most important sentence on
   the site. The selector has to outrank the general dark-ground paragraph rule. */
.section--dark .pledge p {
  font-size: var(--size-lead); line-height: 1.55; max-width: 58ch; color: var(--on-dark);
}

/* --------------------------------------------------------------------------
   12. Numbered steps. Not cards. Typography and a hairline.
   -------------------------------------------------------------------------- */

.steps { display: grid; gap: var(--s6); counter-reset: step; }
@media (min-width: 720px) { .steps { grid-template-columns: repeat(3, 1fr); gap: var(--gutter); } }
.step { border-top: var(--hairline) solid var(--line); padding-top: var(--s4); }
.step .n {
  font-family: var(--mono); font-weight: 500; font-size: 1.25rem;
  color: var(--ink-2); display: block; margin-bottom: var(--s3);
  font-variant-numeric: tabular-nums;
}
.step h3 { margin-bottom: var(--s3); }
.step p { color: var(--ink-2); max-width: var(--measure-bullet); }
:is(.section--dark, .hero) .step { border-top-color: var(--line-dark); }
:is(.section--dark, .hero) .step .n { color: var(--on-dark-3); }

/* --------------------------------------------------------------------------
   13. Pricing
   -------------------------------------------------------------------------- */

.price-pair { display: grid; gap: var(--s5); }
@media (min-width: 900px) { .price-pair { grid-template-columns: 1fr 1fr; gap: var(--gutter); } }

.price { display: flex; flex-direction: column; gap: var(--s4); }
.price h3 { margin: 0; }
.price-figure { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4); }
.price-figure .time {
  font-family: var(--sans); font-weight: 500; font-size: var(--size-meta);
  color: var(--ink-2); text-align: right;
}
.price hr { border: 0; border-top: var(--hairline) solid var(--line); margin: 0; }
.price .list { flex: 1; }
/* The card already sets the measure, so the bullets use its full width. */
.price .list > li,
.offer-band .list > li,
.qtile .note { max-width: none; }
.price .link-cta { align-self: start; }

/* Terms read better as two short columns than as one tall grey block. */
.terms { margin-top: var(--s5); display: grid; gap: var(--s5); }
.terms p { font-size: var(--size-small); color: var(--ink-2); max-width: 52ch; }
@media (min-width: 900px) { .terms { grid-template-columns: 1fr 1fr; gap: var(--s8); } }

/* The shared action beneath the pair. The free check is the door both
   prices are behind, so there is one button, not one per card. */
.price-action {
  margin-top: var(--s7); padding-top: var(--s6);
  border-top: var(--hairline) solid var(--line);
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: var(--s5) var(--s6);
}
.price-action p { max-width: 46ch; margin: 0; }

/* A different shape, because it answers a different question. */
.offer-band {
  margin-top: var(--s9);
  background: var(--paper);
  border-radius: var(--radius);
  padding: var(--s6);
  display: grid; gap: var(--s5);
}
@media (min-width: 900px) { .offer-band { grid-template-columns: 5fr 7fr; gap: var(--s8); padding: var(--s7); } }
.offer-band .figure { margin-block: var(--s3); }
.offer-band .label { border-top: 0; padding-top: 0; }

/* The quiet fourth. Rows, not cards. */
.also { margin-top: var(--s9); }
.also li {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s5);
  padding-block: var(--s4);
  border-top: var(--hairline) solid var(--line);
  font-size: var(--size-small); max-width: none;
}
.also li:last-child { border-bottom: var(--hairline) solid var(--line); }
.also .price-of { font-family: var(--mono); font-weight: 500; font-variant-numeric: tabular-nums;
                  color: var(--ink-2); text-align: right; white-space: nowrap; }
/* The Shopify row carries two figures, which will not sit beside a sentence on a
   small phone. Below 560px the price drops under its description rather than
   being squeezed or wrapped mid-number. */
@media (max-width: 559px) {
  .also li { display: block; }
  .also .price-of { display: block; text-align: left; margin-top: var(--s2); }
}
.also .meta { margin-top: var(--s4); }

/* --------------------------------------------------------------------------
   14. Tier comparison. Three parallel definition lists, not a table, so the
   same markup stacks on a phone and aligns in columns on a laptop.

   Row alignment is structural, not a coincidence of equal label lengths: the
   tier grid declares its rows, each tier takes them with subgrid, and each
   list takes the rows below the head.

   The row count is detected from the markup rather than kept in sync by hand.
   A mismatch here does not degrade, it overlaps rows on top of each other, so
   the ladder below reads the number of rows off the first list and sets the
   spans to match. Add a row to the markup and the layout follows.
   -------------------------------------------------------------------------- */

.tiers { --tier-rows: 6; --tier-span: 7; display: grid; gap: var(--s5); }

.tiers:has(dl > :nth-child(3))  { --tier-rows: 3;  --tier-span: 4;  }
.tiers:has(dl > :nth-child(4))  { --tier-rows: 4;  --tier-span: 5;  }
.tiers:has(dl > :nth-child(5))  { --tier-rows: 5;  --tier-span: 6;  }
.tiers:has(dl > :nth-child(6))  { --tier-rows: 6;  --tier-span: 7;  }
.tiers:has(dl > :nth-child(7))  { --tier-rows: 7;  --tier-span: 8;  }
.tiers:has(dl > :nth-child(8))  { --tier-rows: 8;  --tier-span: 9;  }
.tiers:has(dl > :nth-child(9))  { --tier-rows: 9;  --tier-span: 10; }
.tiers:has(dl > :nth-child(10)) { --tier-rows: 10; --tier-span: 11; }

.tier {
  background: var(--surface);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  padding: var(--s5);
}
@media (min-width: 720px) { .tier { padding: var(--s6); } }

.tier-head { margin-bottom: var(--s4); }
.tier-head h3 { margin-bottom: var(--s3); }

/* Each row is one grid item, so its rule is a single continuous line rather
   than two cell borders at different heights. <div> inside <dl> is valid. */
.tier dl { display: grid; }
.tier-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4);
  padding-block: var(--s3);
  border-bottom: var(--hairline) solid var(--line);
}
.tier-row:last-child { border-bottom: 0; padding-bottom: 0; }
.tier-row dt { font-family: var(--sans); font-weight: 500; font-size: var(--size-meta);
               color: var(--ink-2); }
.tier-row dd { font-size: var(--size-small); text-align: right; white-space: nowrap; }
.tier-row dd.num { font-family: var(--mono); font-weight: 500; font-variant-numeric: tabular-nums; }

/* Below 900px the tiers stack, and three stacked cards of seven rows each is a
   long scroll on a phone. The two larger tiers collapse behind a control whose
   label carries both their prices, so what is hidden is the detail and never a
   number a reader needs in order to decide whether to open it.

   The stylesheet owns the visibility and the script only sets a class. That way
   the breakpoint and the collapsed state cannot disagree: crossing 900px is
   handled entirely in CSS, with no resize listener to miss an event, and a
   reader who collapses on a phone and then rotates to landscape sees all three
   without the script doing anything. */
.tiers-toggle { margin-top: var(--s5); width: 100%; }
.tiers-toggle[hidden] { display: none; }

@media (max-width: 899px) {
  .tiers.is-collapsed .tier--extra { display: none; }
}

@media (min-width: 900px) {
  .tiers-toggle { display: none; }
  .tiers { grid-template-columns: repeat(3, 1fr); gap: var(--gutter);
           grid-template-rows: auto repeat(var(--tier-rows), auto); }
  .tier { display: grid; grid-template-rows: subgrid; grid-row: span var(--tier-span); }
  .tier dl { grid-template-rows: subgrid; grid-row: span var(--tier-rows); }
}

/* A plain document: the privacy policy, and anything else meant to be read
   straight through rather than scanned. Narrow measure, clear headings, no
   marketing furniture of any kind. */
.container--narrow { max-width: 760px; }
.doc h1 { max-width: 24ch; margin-bottom: var(--s5); }
.doc .lead { margin-bottom: var(--s4); }
.doc-body { margin-top: var(--s8); }
.doc-body h2 {
  font-size: var(--size-h3); max-width: none;
  margin-top: var(--s8); padding-top: var(--s4);
  border-top: var(--hairline) solid var(--line);
}
.doc-body > h2:first-child { margin-top: 0; }
.doc-body h3 {
  font-size: var(--size-body); letter-spacing: 0; margin-top: var(--s6);
}
.doc-body > * + * { margin-top: var(--s5); }
.doc-body h2 + p, .doc-body h3 + p { margin-top: var(--s3); }

/* A list that runs in two columns once there is room for it. */
@media (min-width: 720px) {
  .list.cols-2 { columns: 2; column-gap: var(--s8); }
  .list.cols-2 > li { break-inside: avoid; max-width: 44ch; }
  .list.cols-2 > li + li { margin-top: 0; }
  .list.cols-2 > li { margin-bottom: var(--s3); }
}
.list.stays > li { max-width: 46ch; }
.list.stays > li + li { margin-top: var(--s4); }

/* The check request: the form on the left, and what the check actually asks
   beside it on the right. The form is first in the source, so on a phone it is
   still the first thing reached and the questions follow as the explanation. */
.request-grid { display: grid; gap: var(--s8); }
@media (min-width: 1000px) {
  /* The same tracks as the section head above it, so the deck and the questions
     share one left edge and the two halves of the section lock together. */
  .request-grid { grid-template-columns: 5fr 6fr; column-gap: var(--s8); align-items: start; }
  .request-grid .input, .request-grid .select { max-width: 100%; }
}
.request-aside .qtiles { grid-template-columns: 1fr; gap: var(--s3); margin-top: var(--s5); }
.request-aside .qtile { padding: var(--s4) var(--s5); gap: var(--s2); }
.request-aside .qtiles-note { margin-top: var(--s4); }
.request-aside > .small { max-width: 52ch; }

/* Two unequal columns: content on the left, the thing you act on at the right. */
.two-col { display: grid; gap: var(--s7); }
@media (min-width: 900px) { .two-col { grid-template-columns: 1fr 1fr; gap: var(--s8); align-items: start; } }
.two-col .price-figure { margin-bottom: var(--s4); }
.two-col .small, .two-col p:not(.label):not(.meta) { max-width: 46ch; }
.two-col .btn { margin-top: var(--s5); }
.two-col .meta { margin-top: var(--s4); }

/* The two report pages, side by side on a laptop and stacked on a phone. Each
   item fills its own column rather than carrying the narrower bullet measure,
   so the block uses the full width of the section above it. */
.report-pages { display: grid; gap: var(--s7); }
.report-pages h3 { margin-bottom: var(--s4); }
.report-pages .list > li { max-width: none; }
@media (min-width: 900px) { .report-pages { grid-template-columns: 1fr 1fr; gap: var(--s8); } }
/* A source line under a cited figure. Small, plain, and always present when a
   number from outside COMPANY.md is used. */
.source { margin-top: var(--s3); font-family: var(--sans); font-weight: 500;
          font-size: var(--size-meta); color: var(--ink-2); max-width: 68ch; }
.source cite { font-style: italic; }

/* The founding client rate. A bordered block rather than a card, so it reads as
   a condition attached to the prices above rather than a fourth thing to buy. */
.founding {
  margin-top: var(--s9);
  border-top: var(--hairline) solid var(--line);
  border-bottom: var(--hairline) solid var(--line);
  padding-block: var(--s6);
}
.founding h3 { margin-bottom: var(--s4); max-width: 54ch; }
/* Its closing rule serves as the action bar's opening one. */
.founding + .price-action { border-top: 0; }
/* The measure cap is for prose. A kicker is a rule, and the block already has
   its own, so the kicker inside it carries neither a width nor a border. */
.founding p:not(.label) { max-width: 62ch; }
.founding .terms { margin-top: 0; }
.founding .label { border-top: 0; padding-top: 0; }

/* A closing note after a multi-column block. Separated by space, not a rule:
   a hairline that stops at 68ch reads as an accident rather than a division. */
.report-note { margin-top: var(--s7); max-width: 68ch; }

/* --------------------------------------------------------------------------
   14b. Numbered task rows. Used on the checklist page to give the substance
   away before the email is asked for. Rows and hairlines, not cards.
   -------------------------------------------------------------------------- */

.tasks { counter-reset: task; }
.tasks li {
  display: grid; grid-template-columns: 2.25rem 1fr; gap: var(--s3);
  padding-block: var(--s4);
  border-top: var(--hairline) solid var(--line);
  max-width: none;
}
.tasks li:last-child { border-bottom: var(--hairline) solid var(--line); }
.tasks li::before {
  counter-increment: task; content: counter(task, decimal-leading-zero);
  font-family: var(--mono); font-weight: 500; font-size: var(--size-small);
  color: var(--ink-2); font-variant-numeric: tabular-nums; line-height: 1.5;
}
.tasks b { display: block; font-family: var(--sans); font-weight: 700; font-size: var(--size-body);
           letter-spacing: -0.005em; }
.tasks span { display: block; font-size: var(--size-small); color: var(--ink-2);
              margin-top: 0.125rem; max-width: 56ch; }
@media (min-width: 900px) {
  /* Two columns, filled row by row so reading order matches the numbering.
     The closing rule goes on the list, so it spans both columns. */
  .tasks { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--s8);
           border-bottom: var(--hairline) solid var(--line); }
  .tasks li:last-child { border-bottom: 0; }
}

/* --------------------------------------------------------------------------
   14c. Questions and answers. Plain, open, no accordion: hiding an answer
   behind a click helps nobody scanning for the one that worries them.
   -------------------------------------------------------------------------- */

.faq > div { border-top: var(--hairline) solid var(--line); padding-top: var(--s4); margin-top: var(--s5); }
.faq > div:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.faq h3 { margin-bottom: var(--s3); max-width: 46ch; }

/* --------------------------------------------------------------------------
   15. Hero
   -------------------------------------------------------------------------- */

.hero { background: var(--ground); padding-block: clamp(3.5rem, 9vw, 7rem) clamp(3.5rem, 8vw, 6rem); }
.hero h1 { max-width: var(--measure-tight); }
.hero .lead { margin-top: var(--s5); max-width: var(--measure-lead); text-wrap: balance; }

/* One lead opts out of balancing. Balance equalises line lengths, which fights
   the unbreakable sentence below and pushed a four-character orphan onto its
   own line at 414px. Only the home page lead needs this: on the others balance
   is what keeps their short last lines from stranding. */
.hero .lead--flow { text-wrap: pretty; }

/* One sentence in the hero is kept whole. Left to itself, every width from
   768 up ends a line on "Websites", which reads as the tail of the sentence
   before it. The pin starts at 560px: measured below that it either fits by
   itself anyway, or it is long enough to strand the few words before it. */
@media (min-width: 560px) { .keep { white-space: nowrap; } }
.hero .actions { margin-top: var(--s7); }
.hero .hero-meta {
  margin-top: var(--s7); padding-top: var(--s4);
  border-top: var(--hairline) solid var(--line-dark);
  font-family: var(--sans); font-weight: 500; font-size: var(--size-meta);
  color: var(--on-dark-3); max-width: none;
}
.hero .hero-meta a { color: var(--on-dark-3); text-decoration: none; }
@media (hover: hover) { .hero .hero-meta a:hover { color: var(--on-dark); text-decoration: underline; } }
.hero .hero-meta .sep { padding-inline: 0.5rem; }

/* The composition comes from three different right edges, not from ornament. */
@media (min-width: 900px) {
  .hero .lead { max-width: 52ch; }
}
@media (max-width: 639px) {
  .hero .hero-meta .sep { display: none; }
  .hero .hero-meta > span { display: block; }
}

/* --------------------------------------------------------------------------
   16. Print. The site is a document, so it should print like one.
   -------------------------------------------------------------------------- */

@media print {
  .site-header, .nav-toggle, .skip, .btn { display: none !important; }
  /* A4 is narrower than the 900px breakpoint, so without this the two larger
     tiers print as nothing at all and the control that reveals them is hidden
     too. Paper has no controls; everything goes on the page. */
  .tiers.is-collapsed .tier--extra { display: block !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .section, .hero, .site-footer { background: #fff !important; padding-block: 1rem; }
  .section--dark *, .hero *, .site-footer * { color: #000 !important; }
  a { color: #000; text-decoration: underline; }
}
