/* ============================================================================
   Rekaro launch page
   ----------------------------------------------------------------------------
   Structure is carried by hairline rules and an asymmetric grid rather than by
   cards and shadows. That is a deliberate choice: a stack of rounded, shadowed,
   evenly spaced boxes is the house style of generated interfaces, and this
   product's whole claim is that it is checkable by a human.

   Every colour, space and duration below comes from tokens.css.
   ============================================================================ */

/* --- reset ---------------------------------------------------------------- */

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

* { margin: 0; }

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

body {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--f-text);
  font-weight: var(--w-body);
  font-size: 1rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: 'kern' 1;
  text-rendering: optimizeLegibility;
}

img, svg { display: block; max-width: 100%; }
button, input, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }

/* One focus treatment for the whole page. Visible on every control, keyboard
   only, and it never depends on colour alone. */
:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: var(--focus-offset);
  border-radius: var(--r-sm);
}
:focus:not(:focus-visible) { outline: none; }

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

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: var(--s-4);
  top: -4rem;
  z-index: 50;
  padding: var(--s-2) var(--s-4);
  background: var(--ink);
  color: var(--ink-inverse);
  border-radius: var(--r-sm);
  transition: top var(--t-fast) var(--ease);
}
.skip-link:focus-visible { top: var(--s-4); }

/* --- page frame ----------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--s-5);
}

@media (min-width: 60rem) {
  .shell { padding-inline: var(--s-7); }
}

/* --- masthead ------------------------------------------------------------- */

.masthead {
  border-bottom: var(--rule-w) solid var(--rule);
  background: var(--surface);
}

.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Wraps so the nav can take a row of its own on a narrow screen. See the
     note on .nav in site.css: the alternative was a second copy of the links. */
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-4);
  padding-block: var(--s-3);
  min-height: 4.25rem;
}

@media (min-width: 62rem) {
  .masthead__inner { flex-wrap: nowrap; padding-block: 0; }
}

.wordmark {
  display: block;
  height: 1.75rem;
  width: auto;
}

@media (min-width: 48rem) {
  .wordmark { height: 2rem; }
}

.masthead__controls {
  display: flex;
  align-items: center;
  gap: var(--s-4);
}

/* Language as three plain words divided by rules. A select would hide two of
   the three markets we are opening in behind a click. */
.langset {
  display: flex;
  align-items: center;
}

.langset__btn {
  padding: var(--s-1) var(--s-2);
  font-size: 0.78rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.01em;
  color: var(--ink-muted);
  border-radius: var(--r-sm);
  transition: color var(--t-fast) var(--ease);
}
.langset__btn + .langset__btn { border-left: var(--rule-w) solid var(--rule); }
.langset__btn:hover { color: var(--ink); }
.langset__btn[aria-pressed='true'] {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--mark);
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

.themetoggle {
  display: grid;
  place-items: center;
  /* 44px, the WCAG 2.5.8 minimum. It was 2rem, and on every generated page this
     is the only control in the masthead. The icon inside stays at 1rem: the
     target grew, the drawing did not. */
  width: 2.75rem; height: 2.75rem;
  color: var(--ink-muted);
  /* --rule against either surface measures about 1.3:1, and this border is the
     button's entire boundary. SC 1.4.11 asks 3:1 of a control boundary. */
  border: var(--rule-w) solid var(--rule-strong);
  border-radius: var(--r-sm);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.themetoggle:hover { color: var(--ink); border-color: var(--rule-strong); }
.themetoggle svg { width: 1rem; height: 1rem; }
/* The icon that matches the mode you are already in is the wrong affordance. */
.themetoggle .i-sun { display: none; }
:root[data-theme='dark'] .themetoggle .i-sun { display: block; }
:root[data-theme='dark'] .themetoggle .i-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .themetoggle .i-sun { display: block; }
  :root:not([data-theme='light']) .themetoggle .i-moon { display: none; }
}

/* --- hero ----------------------------------------------------------------- */

main { flex: 1; }

.hero {
  display: grid;
  gap: var(--s-7);
  padding-block: var(--s-7) var(--s-8);
}

@media (min-width: 62rem) {
  .hero {
    grid-template-columns: 7fr 5fr;
    gap: var(--s-9);
    align-items: start;
    padding-block: var(--s-9) var(--s-10);
  }
}

.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-size: 0.72rem;
  font-weight: var(--w-strong);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* A short ochre rule instead of a pill badge. Badges read as template. */
.eyebrow::before {
  content: '';
  width: var(--s-6);
  height: 2px;
  background: var(--mark);
  flex: none;
}

.hero__title {
  margin-top: var(--s-5);
  font-family: var(--f-display);
  font-weight: var(--w-display);
  font-size: clamp(2.5rem, 1.35rem + 5vw, 5.75rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
  text-wrap: balance;
}

/* Optical sizing is why Literata is here: at display size the serifs thin out
   and the counters open, which is what keeps a 5rem headline from looking set
   in a body face. */
@supports (font-variation-settings: 'opsz' 60) {
  .hero__title { font-variation-settings: 'opsz' 60; }
}

.hero__title em {
  font-style: normal;
  color: var(--accent);
}

.hero__deck {
  margin-top: var(--s-5);
  max-width: var(--measure);
  font-size: clamp(1.06rem, 1rem + 0.3vw, 1.24rem);
  line-height: 1.62;
  color: var(--ink-secondary);
  text-wrap: pretty;
}

.hero__deck + .hero__deck { margin-top: var(--s-4); }

/* --- signup form ---------------------------------------------------------- */

.signup { margin-top: var(--s-7); max-width: 30rem; }

.signup__row {
  display: grid;
  gap: var(--s-3);
}

@media (min-width: 30rem) {
  .signup__row { grid-template-columns: 1fr auto; align-items: end; }
}

.field { display: flex; flex-direction: column; gap: var(--s-2); }

.field__label {
  font-size: 0.78rem;
  font-weight: var(--w-strong);
  letter-spacing: 0.01em;
  color: var(--ink-muted);
}

/* Underline rather than a box. A boxed, rounded, grey-bordered input is the
   default of every component kit; a ruled line is how a form is printed. */
.field__input {
  width: 100%;
  padding: var(--s-2) 0;
  background: none;
  border: 0;
  border-bottom: 2px solid var(--rule-strong);
  border-radius: 0;
  color: var(--ink);
  transition: border-color var(--t-base) var(--ease);
}
.field__input::placeholder { color: var(--ink-faint); }
.field__input:hover { border-bottom-color: var(--ink-muted); }
.field__input:focus { outline: none; border-bottom-color: var(--accent); }
.field__input:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: var(--focus-offset);
}
.field__input[aria-invalid='true'] { border-bottom-color: var(--error); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-5);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: var(--w-strong);
  font-size: 0.94rem;
  letter-spacing: 0.01em;
  border-radius: var(--r-md);
  transition: background var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.btn:hover { background: var(--accent-hover); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: 0.55; cursor: not-allowed; }
.btn[disabled]:active { transform: none; }

.signup__consent {
  margin-top: var(--s-4);
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--ink-muted);
}
.signup__consent a { color: var(--ink-secondary); text-underline-offset: 2px; }
.signup__consent a:hover { color: var(--accent); }

/* Live region. Reserves no space until it has something to say. */
.signup__status { margin-top: var(--s-4); font-size: 0.9rem; }
/* Not display:none. A live region removed from the accessibility tree cannot
   announce the thing that just put text into it: the node appears and is
   populated in the same frame, and the announcement is dropped. Collapsing the
   margin gets the same layout without ever taking the region out of the tree. */
.signup__status:empty { margin-top: 0; }
.signup__status:focus { outline: none; }
.signup__status[data-state='error'] { color: var(--error); }
.signup__status[data-state='ok'] {
  padding-top: var(--s-3);
  border-top: var(--rule-w) solid var(--rule);
  color: var(--accent);
}

/* Bot trap. Off-screen rather than display:none, because some fillers skip
   hidden fields. Real people never reach it; it is not focusable or announced. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  opacity: 0;
}

/* --- register panel ------------------------------------------------------- */

.register {
  border-top: 2px solid var(--ink);
  padding-top: var(--s-4);
}

@media (min-width: 62rem) {
  .register { margin-top: var(--s-2); }
}

.register__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  padding-bottom: var(--s-4);
}

.register__title {
  font-size: 0.78rem;
  font-weight: var(--w-strong);
  letter-spacing: 0.02em;
}

.register__meta {
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.register__list { list-style: none; padding: 0; }

.register__row {
  padding-block: var(--s-4);
  border-top: var(--rule-w) solid var(--rule);
}


.register__name {
  font-weight: var(--w-medium);
  line-height: 1.4;
}

.register__note {
  margin-top: var(--s-1);
  font-size: 0.86rem;
  color: var(--ink-muted);
  line-height: 1.5;
}

.register__state {
  display: inline-block;
  margin-top: var(--s-2);
  font-size: 0.7rem;
  font-weight: var(--w-strong);
  letter-spacing: 0.02em;
  color: var(--ink-secondary);
  padding: 0.15rem var(--s-2);
  border: var(--rule-w) solid var(--rule-strong);
  border-radius: var(--r-sm);
}
.register__state[data-state='building'] {
  color: var(--accent);
  border-color: var(--accent);
}

/* --- icons ---------------------------------------------------------------- */

/* The sprite is inlined into the document rather than referenced as a file.
   An external SVG cannot see the page's custom properties, so the one ochre
   mark in each icon would fall back to nothing. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.register__row-head {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
}

.register__icon {
  width: 1.15rem;
  height: 1.15rem;
  flex: none;
  color: var(--ink-muted);
  transform: translateY(0.18rem);
}

/* --- provenance chain ----------------------------------------------------- */

.chain {
  margin: 0;
  padding-block: var(--s-6) var(--s-8);
  border-top: var(--rule-w) solid var(--rule);
}

.chain__svg {
  display: block;
  width: 100%;
  height: auto;
  max-width: 70rem;
  margin-inline: auto;
  overflow: visible;
}

.chain__label {
  font-family: var(--f-text);
  font-size: 15px;
  font-weight: var(--w-strong);
  fill: var(--ink);
  letter-spacing: 0.01em;
}

.chain__meta {
  font-family: var(--f-text);
  font-size: 12.5px;
  fill: var(--ink-faint);
}

/* One orchestrated entry, then it stops. The trace draws left to right so the
   eye follows the claim in the headline: rating, verification, source. Nothing
   here loops, pulses or floats. */
@media (prefers-reduced-motion: no-preference) {
  .chain__line {
    stroke-dasharray: 140;
    stroke-dashoffset: 140;
    animation: draw 380ms var(--ease) both;
  }
  .chain__line--2 { animation-delay: 520ms; }

  .chain__arrow path { opacity: 0; animation: fade 200ms var(--ease) both; }
  .chain__arrow path:first-child { animation-delay: 380ms; }
  .chain__arrow path:last-child { animation-delay: 900ms; }

  .chain__node { opacity: 0; animation: rise 300ms var(--ease) both; }
  .chain__node[data-step='2'] { animation-delay: 420ms; }
  .chain__node[data-step='3'] { animation-delay: 940ms; }

  .chain__check {
    stroke-dasharray: 46;
    stroke-dashoffset: 46;
    animation: draw 260ms var(--ease) both;
    animation-delay: 700ms;
  }

  @keyframes draw { to { stroke-dashoffset: 0; } }
  @keyframes fade { to { opacity: 1; } }
}

/* Without motion the finished picture renders immediately. Same image, no
   drawing. Nothing is hidden from anyone who cannot see the animation. */
@media (prefers-reduced-motion: reduce) {
  .chain__line, .chain__check { stroke-dashoffset: 0; }
  .chain__node, .chain__arrow path { opacity: 1; }
}

@media (max-width: 46rem) {
  /* Three cards side by side stop being readable well before the viewport
     runs out, so below this the chain is replaced by the list it describes. */
  .chain { display: none; }
}

/* --- team ----------------------------------------------------------------- */

.team {
  border-top: var(--rule-w) solid var(--rule);
  padding-block: var(--s-7);
}

.team__title {
  font-size: 0.78rem;
  font-weight: var(--w-strong);
  letter-spacing: 0.02em;
  color: var(--ink-muted);
}

.team__founders {
  list-style: none;
  padding: 0;
  margin-top: var(--s-5);
  display: grid;
  gap: var(--s-5);
}

@media (min-width: 40rem) {
  .team__founders { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-6); }
}

.team__name {
  font-family: var(--f-display);
  font-weight: var(--w-display);
  font-size: clamp(1.3rem, 1.15rem + 0.6vw, 1.7rem);
  line-height: 1.15;
  letter-spacing: -0.012em;
}

.team__role {
  margin-top: var(--s-1);
  font-size: 0.88rem;
  color: var(--ink-muted);
}

.team__figures {
  margin: var(--s-7) 0 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: var(--rule-w) solid var(--rule);
}

.figure {
  padding-top: var(--s-4);
  padding-right: var(--s-4);
}
.figure + .figure {
  padding-left: var(--s-4);
  border-left: var(--rule-w) solid var(--rule);
}

/* Label above value. A count is only meaningful once you know what is being
   counted, and reading order should match that. */
.figure__label {
  font-size: 0.7rem;
  font-weight: var(--w-strong);
  letter-spacing: 0.02em;
  color: var(--ink-faint);
}

.figure__value {
  margin: var(--s-2) 0 0;
  font-family: var(--f-display);
  font-weight: var(--w-display);
  font-size: clamp(2rem, 1.6rem + 1.6vw, 3rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* --- colophon ------------------------------------------------------------- */

.colophon {
  border-top: var(--rule-w) solid var(--rule);
  background: var(--surface-sunk);
  padding-block: var(--s-6);
  font-size: 0.86rem;
  color: var(--ink-muted);
}

.colophon__grid {
  display: grid;
  gap: var(--s-5);
}

@media (min-width: 48rem) {
  .colophon__grid { grid-template-columns: repeat(3, 1fr); gap: var(--s-6); }
  .colophon__grid--two { grid-template-columns: repeat(2, minmax(0, 24rem)); }
}

.colophon__label {
  font-size: 0.7rem;
  font-weight: var(--w-strong);
  letter-spacing: 0.02em;
  color: var(--ink-faint);
  margin-bottom: var(--s-2);
}

.colophon p + p { margin-top: var(--s-1); }
.colophon a { color: var(--ink-secondary); text-underline-offset: 2px; }
.colophon a:hover { color: var(--accent); }

.colophon__legal {
  margin-top: var(--s-6);
  padding-top: var(--s-4);
  border-top: var(--rule-w) solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  justify-content: space-between;
  font-size: 0.78rem;
  color: var(--ink-faint);
}

/* --- error pages --------------------------------------------------------- */

/* One large mark, in ochre, above the message. An error page with nothing on it
   but grey text reads as a dead end; an icon that names the failure gives the
   eye somewhere to land before the sentence. */
.errpage__icon {
  width: 3.25rem;
  height: 3.25rem;
  color: var(--mark);
  margin-bottom: var(--s-5);
}

@media (prefers-reduced-motion: no-preference) {
  .errpage__icon { animation: rise 320ms var(--ease) both; }
}

/* --- offline ------------------------------------------------------------- */

.offline {
  flex: 1;
  display: grid;
  place-content: center;
  padding-block: var(--s-9);
}

.offline__title {
  margin-top: var(--s-5);
  font-family: var(--f-display);
  font-weight: var(--w-display);
  font-size: clamp(1.9rem, 1.4rem + 2vw, 2.9rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.offline__body {
  margin-top: var(--s-4);
  max-width: 32rem;
  color: var(--ink-secondary);
}
.offline__body--alt { color: var(--ink-muted); font-size: 0.92rem; }

.offline__retry { margin-top: var(--s-6); justify-self: start; text-decoration: none; }

/* --- entrance ------------------------------------------------------------- */

/* One short rise, staggered by a few frames so the eye lands on the headline
   first. Nothing loops, nothing floats, nothing glows. */
/* The stagger is a class rather than an inline custom property, because the
   page ships a strict Content-Security-Policy and style-src 'self' blocks style
   attributes outright. Loosening the policy to keep five inline declarations
   would be the wrong trade. */
@media (prefers-reduced-motion: no-preference) {
  .rise {
    animation: rise var(--t-slow) var(--ease) both;
  }
  .rise--2 { animation-delay: 60ms; }
  .rise--3 { animation-delay: 120ms; }
  .rise--4 { animation-delay: 150ms; }
  .rise--5 { animation-delay: 200ms; }
  .rise--6 { animation-delay: 260ms; }

  @keyframes rise {
    from { opacity: 0; transform: translateY(0.6rem); }
    to   { opacity: 1; transform: none; }
  }
}

/* --- hero sourcing figure -------------------------------------------------- */

/* Replaces the register panel in the hero's right column. It shows the product
   doing its job rather than illustrating around it: a need, a field of
   candidates, and a ranked shortlist with the reason for each rank visible.
   Density is the point, a buyer reads it as competence, but every mark is a
   hairline, a tabular number or a bar. Nothing glows, nothing floats, and the
   whole sequence plays once. */

.sourcing { margin: 0; }
.sourcing__svg { display: block; width: 100%; height: auto; overflow: visible; }

.src__label {
  font-family: var(--f-text); font-size: 11px; font-weight: 620;
  letter-spacing: 0.1em; fill: var(--ink-muted); text-transform: none;
}
.src__need-text { font-family: var(--f-text); font-size: 14.5px; fill: var(--ink); }
.src__meta { font-family: var(--f-text); font-size: 11px; fill: var(--ink-faint);
             font-variant-numeric: tabular-nums; }
.src__dot { fill: var(--rule-strong); }
.src__name { font-family: var(--f-text); font-size: 14px; font-weight: 500; fill: var(--ink); }
.src__sub  { font-family: var(--f-text); font-size: 11.5px; fill: var(--ink-faint); }
.src__score {
  font-family: var(--f-display); font-size: 17px; fill: var(--ink);
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: no-preference) {
  /* The field settles first, then a single pass of the scan line, then the
     shortlist resolves. One sequence, about 1.6s, then it is a static diagram. */
  .src__need { opacity: 0; animation: rise 320ms var(--ease) both; }

  /* Delays as nth-child buckets rather than an inline custom property. The
     page ships style-src 'self', which blocks style attributes outright, and
     loosening the policy for 50 timing values would be the wrong trade. */
  .src__dot { opacity: 0; animation: dot 260ms var(--ease) both; }
  .src__dot:nth-child(12n+1) { animation-delay: 40ms; }
  .src__dot:nth-child(12n+2) { animation-delay: 62ms; }
  .src__dot:nth-child(12n+3) { animation-delay: 84ms; }
  .src__dot:nth-child(12n+4) { animation-delay: 106ms; }
  .src__dot:nth-child(12n+5) { animation-delay: 128ms; }
  .src__dot:nth-child(12n+6) { animation-delay: 150ms; }
  .src__dot:nth-child(12n+7) { animation-delay: 172ms; }
  .src__dot:nth-child(12n+8) { animation-delay: 194ms; }
  .src__dot:nth-child(12n+9) { animation-delay: 216ms; }
  .src__dot:nth-child(12n+10) { animation-delay: 238ms; }
  .src__dot:nth-child(12n+11) { animation-delay: 260ms; }
  .src__dot:nth-child(12n+12) { animation-delay: 282ms; }
  @keyframes dot { to { opacity: 1; } }

  .src__scanline {
    opacity: 0;
    animation: scan 620ms var(--ease) 420ms both;
  }
  @keyframes scan {
    0%   { opacity: 0; transform: translateY(0); }
    12%  { opacity: 1; }
    88%  { opacity: 1; }
    100% { opacity: 0; transform: translateY(84px); }
  }

  /* Dots the scan has passed fade back, so the field visibly narrows rather
     than just sitting there. */
  .src__dots { animation: dim 400ms var(--ease) 900ms both; }
  @keyframes dim { to { opacity: 0.35; } }

  .src__list { opacity: 0; animation: rise 300ms var(--ease) 860ms both; }

  .src__row { opacity: 0; animation: rise 300ms var(--ease) both; }
  .src__bar { transform-origin: 428px 0; animation: grow 420ms var(--ease) both; }
  .src__row:nth-of-type(1) { animation-delay: 900ms; }
  .src__row:nth-of-type(1) .src__bar { animation-delay: 1020ms; }
  .src__row:nth-of-type(2) { animation-delay: 1010ms; }
  .src__row:nth-of-type(2) .src__bar { animation-delay: 1130ms; }
  .src__row:nth-of-type(3) { animation-delay: 1120ms; }
  .src__row:nth-of-type(3) .src__bar { animation-delay: 1240ms; }
  .src__row:nth-of-type(4) { animation-delay: 1230ms; }
  .src__row:nth-of-type(4) .src__bar { animation-delay: 1350ms; }
  @keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
}

@media (prefers-reduced-motion: reduce) {
  .src__need, .src__dot, .src__list, .src__row { opacity: 1; }
  .src__dots { opacity: 0.35; }
  .src__scanline { opacity: 0; }
}

/* The cutoff was 62rem, which took the densest figure on the site off every
   tablet and every laptop window under 992px. In the single-column layout the
   figure simply drops full width under the hero copy and is perfectly legible
   there. It goes at 46rem, the width where its own 14px labels stop being
   readable rather than merely small, which is the same place .chain gives up. */
@media (max-width: 46rem) { .sourcing { display: none; } }


/* --- reduced motion, the part the keyframe gates miss ---------------------- */

/* Every animation on this site is declared inside a
   prefers-reduced-motion: no-preference block, which is the right way round.
   Transitions are not, and they are motion too: the skip link slides down, the
   inputs move their underline colour, and .btn:active translates the button a
   pixel on every press. Rather than adding a query to each one, this is the
   backstop. Durations go to near-zero instead of zero so transitionend and
   animationend still fire and no script waiting on them hangs. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .btn:active { transform: none; }
}

/* The skip link moves the scroll position but not the focus in Safari and
   Firefox unless the target can hold it, so the next Tab goes back to the
   masthead and the link achieves nothing for the visitors it exists for. */
main:focus { outline: none; }
