/* ==========================================================================
   Base layer — reset, element defaults, layout primitives, accessibility
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Paired with the same rule on body. A fixed overlay that is only
     visibility:hidden still contributes to scrollWidth, so both elements need
     the guard or a phone gets a sideways scrollbar. */
  overflow-x: hidden;
  /* Offset anchor targets so sticky nav never covers a jumped-to heading. */
  scroll-padding-top: var(--space-24);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  letter-spacing: var(--tracking-normal);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-kerning: normal;
  font-variant-numeric: tabular-nums lining-nums;
  overflow-x: hidden; /* asymmetric layouts must never scroll the body sideways */
}

/* ---- Film grain ---------------------------------------------------------
   A single fixed pseudo-element carrying an inline SVG noise texture. Fixed
   and pointer-events:none so it never triggers repaints while scrolling —
   attaching grain to a scrolling container is a guaranteed frame-rate loss.
   At 3% it is invisible as texture but stops large cream areas reading flat. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.028;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---- Headings -----------------------------------------------------------
   Display serif, tight leading, negative tracking. Balanced wrapping stops
   the widow-on-its-own-line problem that makes big type look accidental. */
h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-weight: 400;
  color: var(--ink);
  text-wrap: balance;
}

h1, h2, h3 {
  font-family: var(--font-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); line-height: var(--leading-snug); }

/* h4-h6 drop to the sans — at these sizes the serif loses its advantage
   and starts to look like a mistake. */
h4, h5, h6 {
  font-family: var(--font-body);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-snug);
  font-weight: 600;
}
h4 { font-size: var(--text-xl); }
h5 { font-size: var(--text-lg); }
h6 {
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
  color: var(--ink-muted);
}

p { margin: 0; }

/* ---- Links --------------------------------------------------------------
   Underlines use an offset border rather than text-decoration so the
   thickness and colour animate independently of the text. */
a {
  color: inherit;
  text-decoration: none;
}

a:not([class]) {
  color: var(--ink);
  border-bottom: 1px solid var(--accent);
  padding-bottom: 0.06em;
  transition: color var(--duration-fast) var(--ease),
              background-color var(--duration-fast) var(--ease),
              border-color var(--duration-fast) var(--ease);
}
a:not([class]):hover {
  color: var(--accent-ink);
  background-color: var(--accent-wash);
  border-color: var(--accent-hover);
}

/* ---- Focus -------------------------------------------------------------
   Visible, high contrast, and only for keyboard users. Never removed. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}
/* On navy grounds the brick ring lacks contrast — switch to cream. */
.is-dark :focus-visible { outline-color: var(--paper); }

/* ---- Media ------------------------------------------------------------- */
img, picture, video, canvas, svg, iframe {
  display: block;
  max-width: 100%;
}
img, video {
  height: auto;
  /* Cream placeholder while loading, so layout never flashes white.
     CAREFUL: this fills the transparent areas of any PNG, WebP or SVG with
     cream, which reads as a solid box behind the artwork. Anything with an
     alpha channel must opt out with `background: none` — see .brand__mark. */
  background-color: var(--paper-warm);
}
/* Vectors are effectively always transparent, so opt them out up front. */
img[src$=".svg"] { background: none; }
svg { fill: currentColor; }

/* ---- Forms ------------------------------------------------------------- */
input, button, textarea, select {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}
button { cursor: pointer; background: none; border: none; padding: 0; }
textarea { resize: vertical; }
::placeholder { color: var(--ink-faint); opacity: 1; }

/* ---- Tables ------------------------------------------------------------ */
table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
th, td { text-align: left; }

hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: var(--space-16) 0;
}

/* Blockquote and code get full treatment in the prose scope below. */
blockquote, figure { margin: 0; }

ul, ol { margin: 0; padding: 0; }
li { list-style: none; }

/* ==========================================================================
   Layout primitives
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--wide { max-width: var(--container-wide); }
.container--text { max-width: var(--container-text); }

/* Section rhythm. Every top-level band uses this so vertical spacing is
   consistent without each page re-deciding. */
.section { padding-block: var(--section-y); }
.section--tight { padding-block: var(--section-y-tight); }
.section--flush-top { padding-top: 0; }

/* Alternating grounds */
.section--warm { background: var(--paper-warm); }
.section--ink {
  background: var(--ink);
  color: var(--paper);
}
.section--ink h1, .section--ink h2, .section--ink h3,
.section--ink h4, .section--ink h5 { color: var(--paper); }
.section--ink h6 { color: rgba(250, 248, 243, 0.6); }

/* Editorial split — the workhorse asymmetric layout. 7/5 on desktop,
   single column below 900px. Never an equal 3-up card row. */
.split {
  display: grid;
  gap: var(--space-12) var(--space-16);
  grid-template-columns: 1fr;
  align-items: start;
}
/* Grid children default to min-width:auto and so refuse to shrink below their
   content. Without this a wide table inside a column stretches the column
   instead of scrolling within its own overflow container. */
.split > *, .bento > * { min-width: 0; }
@media (min-width: 56.25rem) {
  .split { grid-template-columns: 7fr 5fr; }
  .split--reverse { grid-template-columns: 5fr 7fr; }
  .split--even    { grid-template-columns: 1fr 1fr; }
  .split--wide-left  { grid-template-columns: 8fr 4fr; }
  .split--wide-right { grid-template-columns: 4fr 8fr; }
  /* Keeps a sidebar column tracking the reader down a long section. */
  .split__sticky { position: sticky; top: var(--space-24); }
}

/* Asymmetric bento. Children opt into spans; everything collapses to one
   column on mobile, where overlapping and spanning cause touch conflicts. */
.bento {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}
@media (min-width: 48rem) {
  .bento { grid-template-columns: repeat(12, 1fr); gap: var(--space-5); }
  .bento > .span-3  { grid-column: span 3; }
  .bento > .span-4  { grid-column: span 4; }
  .bento > .span-5  { grid-column: span 5; }
  .bento > .span-6  { grid-column: span 6; }
  .bento > .span-7  { grid-column: span 7; }
  .bento > .span-8  { grid-column: span 8; }
  .bento > .span-12 { grid-column: span 12; }
  .bento > .row-2   { grid-row: span 2; }
}

.stack > * + * { margin-top: var(--flow, var(--space-4)); }

/* Inline children ignore the margin-top above and run together on one line —
   which is how the footer's phone and email ended up as a single unbroken
   string. Promote the inline elements actually used inside a stack. */
.stack > a,
.stack > span,
.stack > time,
.stack > strong,
.stack > em,
.stack > small { display: block; }

/* Block makes each link take its own line, but a full-width block also drags
   its underline across the whole column. fit-content keeps the rule under the
   text where it belongs. inline-block would not work here: siblings that fit
   would flow back onto one line. */
.stack > a { width: fit-content; }
.stack--sm { --flow: var(--space-2); }
.stack--lg { --flow: var(--space-6); }
.stack--xl { --flow: var(--space-10); }

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.measure       { max-width: var(--measure); }
.measure--tight { max-width: var(--measure-tight); }

/* ==========================================================================
   Text utilities
   ========================================================================== */

/* Eyebrow — the small mono label that precedes major headings. */
.eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
  color: var(--ink-muted);
  margin-bottom: var(--space-5);
}
.section--ink .eyebrow { color: rgba(250, 248, 243, 0.62); }

/* Pill variant, used where an eyebrow needs more presence. */
.eyebrow--pill {
  display: inline-block;
  margin-bottom: var(--space-6);
  padding: 0.4em 0.85em;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  color: var(--ink-soft);
  background: var(--white);
}
.section--ink .eyebrow--pill {
  border-color: var(--rule-ink);
  background: rgba(250, 248, 243, 0.05);
  color: var(--paper);
}

.lede {
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
  color: var(--ink-muted);
  letter-spacing: var(--tracking-snug);
}
.section--ink .lede { color: rgba(250, 248, 243, 0.76); }

.display   { font-family: var(--font-display); letter-spacing: var(--tracking-tight); line-height: var(--leading-tight); }
.display--hero { font-size: var(--text-5xl); }
/* Italic serif for emphasised phrases inside a display heading. */
.display em { font-style: italic; }

.mono {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
}

.text-muted   { color: var(--ink-muted); }
.text-faint   { color: var(--ink-faint); }
.text-accent  { color: var(--accent-ink); }
.text-center  { text-align: center; }

/* ==========================================================================
   Prose — long-form article body. Scoped so it never leaks into components.
   ========================================================================== */

.prose {
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--ink);
}
.prose > * + * { margin-top: var(--space-6); }

/* Page-builder content nests paragraphs and lists several divs deep, so the
   direct-child rule above never reaches them and consecutive paragraphs run
   together with no gap at all. Restore the rhythm at any depth. Headings carry
   their own margins below, so they are unaffected. This can go once the four
   old posts are rebuilt as plain content. */
.prose p + p,
.prose p + ul, .prose p + ol,
.prose ul + p, .prose ol + p,
.prose ul + ul, .prose ol + ol,
.prose p + blockquote, .prose blockquote + p { margin-top: var(--space-6); }

.prose h2 {
  font-size: var(--text-2xl);
  margin-top: var(--space-16);
  margin-bottom: var(--space-5);
}
.prose h3 {
  font-size: var(--text-xl);
  font-family: var(--font-body);
  font-weight: 600;
  letter-spacing: var(--tracking-snug);
  margin-top: var(--space-12);
  margin-bottom: var(--space-4);
}
.prose h2 + *, .prose h3 + * { margin-top: 0; }

.prose ul, .prose ol {
  padding-left: var(--space-6);
  display: grid;
  gap: var(--space-3);
}
.prose li { list-style: revert; }
.prose li::marker { color: var(--accent-ink); }

.prose a {
  color: var(--ink);
  border-bottom: 1px solid var(--accent);
  transition: background-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease);
}
.prose a:hover { color: var(--accent-ink); background: var(--accent-wash); }

.prose strong { font-weight: 600; }

.prose blockquote {
  margin-block: var(--space-12);
  padding: var(--space-8) var(--space-10);
  background: var(--paper-deep);
  border-radius: var(--radius-lg);
  border-left: 2px solid var(--accent);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-snug);
}
.prose blockquote p + p { margin-top: var(--space-4); }
.prose blockquote cite {
  display: block;
  margin-top: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-style: normal;
  letter-spacing: var(--tracking-wide);
  color: var(--ink-muted);
}

.prose figure { margin-block: var(--space-12); }
.prose img { border-radius: var(--radius-md); }
.prose figcaption {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.prose code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--paper-deep);
  padding: 0.15em 0.4em;
  border-radius: var(--radius-sm);
}

.prose table {
  margin-block: var(--space-10);
  font-size: var(--text-sm);
}
.prose th, .prose td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
}
.prose th {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
  color: var(--ink-muted);
  font-weight: 500;
}

/* Any wide element inside prose scrolls in its own container rather than
   pushing the page sideways. */
.prose .scroll-x {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Any horizontally scrolling region must be capped at its container width,
   or it silently widens the page instead of scrolling. */
.scroll-x, .data-table-wrap { max-width: 100%; }

/* ==========================================================================
   Scroll reveal
   Elements start displaced and blurred; site.js adds .is-visible via
   IntersectionObserver. Only transform, opacity and filter animate.
   ========================================================================== */

.reveal {
  opacity: 0;
  transform: translate3d(0, 2.5rem, 0);
  filter: blur(6px);
  transition: opacity var(--duration-reveal) var(--ease-out),
              transform var(--duration-reveal) var(--ease-out),
              filter var(--duration-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.reveal.is-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  filter: blur(0);
}

/* Stagger helpers for sibling groups. */
.reveal-2 { --reveal-delay: 90ms; }
.reveal-3 { --reveal-delay: 180ms; }
.reveal-4 { --reveal-delay: 270ms; }
.reveal-5 { --reveal-delay: 360ms; }

/* No JS, or reduced motion: show everything immediately. Content must never
   depend on JavaScript to become visible. */
.no-js .reveal,
html:not(.js) .reveal {
  opacity: 1;
  transform: none;
  filter: none;
}
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; filter: none; transition: none; }
}

/* ==========================================================================
   Accessibility
   ========================================================================== */

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
  z-index: var(--z-modal);
  padding: var(--space-3) var(--space-5);
  background: var(--ink);
  color: var(--paper);
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: 500;
  transform: translateY(-160%);
  transition: transform var(--duration-base) var(--ease);
}
.skip-link:focus-visible { transform: translateY(0); }

/* Stops the whole page animating while the viewport is being resized. */
.is-resizing * { transition: none !important; }
