/* ============================================================================
   RIDDLE & COGHILL — BASE / RESET / TYPOGRAPHY / LAYOUT PRIMITIVES
   ========================================================================== */

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

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

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background-color var(--transition), color var(--transition);
}

img, video, svg { max-width: 100%; display: block; height: auto; }

a { color: inherit; text-decoration: none; }

button { font-family: inherit; cursor: pointer; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--c-heading);
  /* Lighter display weight: the serif carries the tone, not the ink. */
  font-weight: 400;
  line-height: var(--lh-tight);
  margin: 0 0 0.5em;
  letter-spacing: -0.005em;
}

/* Roman + italic mix inside a display heading — the phrase gets the emphasis,
   never a second typeface. */
h1 em, h2 em, h3 em,
.display-em {
  font-style: italic;
  font-weight: 400;
  color: inherit;
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); font-weight: 600; letter-spacing: 0; }

p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

/* ---- Reduced motion ---------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* ---- Layout primitives -------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-width: var(--container-narrow); }

.section { padding-block: var(--section-y); }
.section--tight { padding-block: clamp(2.5rem, 5vw, 4rem); }

/* Two sections in a row with no background between them.

   Every other boundary on this site puts a colour change in the middle of the
   gap - .section--alt, .section--inverse, .band - so the two paddings read as
   "end of one thing, start of another" and the eye never dwells on the space.
   Where both sections sit on the page ground there is no such landmark, and
   the same 2 x --section-y (317px at desktop) collapses into a single
   uninterrupted void. It is the only place the spacing looks like a mistake.

   Dropping the second section's top pad leaves one --section-y between them,
   which is exactly the space the reader already reads as "clear air before a
   heading" everywhere else. .section--tight and .section--flush set their own
   padding deliberately and are left alone. */
.section:not(.section--alt):not(.section--inverse):not(.section--tight):not(.section--flush)
  + .section:not(.section--alt):not(.section--inverse):not(.section--tight):not(.section--flush) {
  padding-top: 0;
}

.section--inverse {
  background: var(--c-inverse-bg);
  color: var(--c-inverse-text);
}
.section--inverse h1,
.section--inverse h2,
.section--inverse h3 { color: var(--c-inverse-heading); }

.section--alt { background: var(--c-surface-alt); }

/* ---- Eyebrow / small caps label ---------------------------------------- */
.eyebrow {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--c-accent);
  margin-bottom: var(--space-4);
}
.section--inverse .eyebrow { color: var(--c-accent); }

.lead {
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--c-text-muted);
}
.section--inverse .lead { color: var(--c-inverse-text); }

.muted { color: var(--c-text-muted); }

/* ---- Utility ------------------------------------------------------------ */
.text-center { text-align: center; }
.mx-auto { margin-inline: auto; }
.measure { max-width: 62ch; }
.measure-tight { max-width: 48ch; }
.stack > * + * { margin-top: var(--space-4); }
.stack-lg > * + * { margin-top: var(--space-6); }
.stack-xl > * + * { margin-top: clamp(3.5rem, 8vw, 6.5rem); }

.grid { display: grid; gap: clamp(1.25rem, 3vw, 2.5rem); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 900px) {
  .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 620px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}

/* Rules carry a trace of the accent rather than being neutral grey — on a site
   this quiet, the hairlines are most of the places colour can live. */
.hairline { border: 0; border-top: var(--border-hairline) solid var(--c-line); margin: 0; }
.hairline { border-top-color: color-mix(in srgb, var(--c-accent) 40%, var(--c-line)); }

/* Accessible focus */
:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
}

/* Skip link */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--c-heading);
  color: var(--c-bg);
  padding: var(--space-3) var(--space-5);
  z-index: 200;
}
.skip-link:focus { left: var(--space-4); top: var(--space-4); }

/* Screen-reader only */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- Reveal-on-scroll (progressive enhancement) ------------------------- */
/* Reveal on scroll. Items inside a group get a small cascade via --reveal-i,
   set by chrome.js — 110ms apart, capped so a 12-item grid never crawls. The
   delay applies to the entrance only: on the way to `is-visible` there is no
   delay to unwind, so nothing feels sticky if the user scrolls straight back. */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity var(--transition-slow) calc(var(--reveal-i, 0) * 110ms),
    transform var(--transition-slow) calc(var(--reveal-i, 0) * 110ms);
}
.reveal.is-visible { opacity: 1; transform: none; }

/* Media blocks don't slide — the image itself uncovers instead. The wipe and
   the scroll parallax both live in the motion layer at the foot of
   components.css; deliberately NOT duplicated here, because a rule like
   `.reveal--media.is-visible .placeholder__img` outranks the parallax
   selector and silently pins the transform to none. */
.reveal--media { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}
/* NOTE: the reveal is JS-driven — without JS these blocks would sit at opacity 0
   forever, so every page carries a <noscript> override in its <head>. */
