/* Spacing scale. Every padding, margin and gap uses one of these. check.py enforces it. */
:root {
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2.25rem;
  --s-7: 3.5rem;
  --s-8: 5.5rem;
  --s-9: 8.5rem;
  --measure: 66ch;
  --gutter: clamp(var(--s-4), 4vw, var(--s-7));
  --hair: 1px;
}
/* Reveal. Give a section data-reveal; give its children --i: 0, 1, 2 for stagger. */
[data-reveal] > * { opacity: 0; transform: translateY(18px); transition: opacity .55s ease, transform .55s ease; transition-delay: calc(var(--i, 0) * 80ms); }
[data-reveal].is-in > * { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { [data-reveal] > * { opacity: 1; transform: none; transition: none; } }
/* Swap component. Desktop: picture beside the list. Mobile: picture pinned under the masthead so a tap is seen. */
[data-swap-pic] img { transition: opacity .15s ease; }
[data-swap-pic].is-swapping img { opacity: 0; }
[data-swap] [data-img] { cursor: pointer; }
@media (max-width: 760px) {
  [data-swap-pic] { position: sticky; top: var(--mast, 3.5rem); z-index: 2; }
  [data-swap-pic] img { aspect-ratio: 4 / 3; object-fit: cover; width: 100%; }
}
/* Colour tokens go in site.css, named after their source: --awning-red, --van-white, --ink. */
*, *::before, *::after { box-sizing: border-box; }
img, svg, video { max-width: 100%; height: auto; display: block; }
body { margin: 0; }
.prose { max-width: var(--measure); }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}
