/* Landing page — IBM Plex Sans + new token system */

/* The sticky section nav (.secnav, in styles.css) landed here on 13 August
   2026, and anchor targets now have to clear the site header AND that bar or
   every jump lands with its heading tucked behind them. The global rule in
   styles.css sets 96px for the header alone; a page carrying the bar needs the
   extra 46. Scoped by loading: pages/landing.css loads only here. */
html { scroll-padding-top: 142px; }

/* ============ HERO (full-width video) ============ */
.hero {
  position: relative;
  background: var(--ink);
  color: var(--paper);
  overflow: hidden;
  min-height: 88vh;
  display: flex;
  align-items: center;
  padding: 100px 0 80px;
}

.hero__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.hero__bg img,
.hero__bg video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.5;
}

/* Scrim over the hero video. Lightened 28 July 2026 so the canopy footage is
   legible as footage rather than as dark texture.

   These numbers are not free-floating: the hero text sits on top of a moving
   image, and this gradient is the only thing guaranteeing it stays readable.
   Worst-case contrast was measured against the brightest pixels of five frames,
   per text band. A flat 10% cut (0.45/0.70/0.79) drops the saffron eyebrow to
   4.47:1, just under AA. Holding the top stop at 0.47 keeps it at 4.58:1 and is
   visually indistinguishable — the video's share of the composite lands at
   18.4% either way, against 15.2% before.

   Measured after this change: eyebrow 4.58, title 8.51, lead 6.59, stat labels
   5.24. If you lighten it further, re-measure — the eyebrow is the binding
   constraint and it has very little headroom. */
.hero__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(17,21,28,0.47) 0%, rgba(17,21,28,0.70) 70%, rgba(17,21,28,0.79) 100%);
}

.hero .container {
  position: relative;
  z-index: 2;
}

.hero__eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--saffron);
  font-weight: 500;
  margin-bottom: 28px;
  max-width: 720px;
}

/* 920px, not 900. "& environmental futures." measures exactly 900px at this
   size, so in a 900px box sub-pixel rounding tipped "futures." onto a third
   line — the title was losing a whole line to a rounding error rather than to
   anything real. Ten more pixels is enough; twenty leaves margin for webfont
   metrics to shift without the third line coming back. */
.hero__title {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(44px, 7vw, 84px);
  line-height: 0.98;
  letter-spacing: -0.035em;
  margin-bottom: 28px;
  max-width: 920px;
}

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

.hero__sub {
  font-family: var(--body);
  font-weight: 300;
  font-size: clamp(17px, 2vw, 21px);
  line-height: 1.5;
  color: #c8c5bd;
  max-width: 680px;
  margin-bottom: 36px;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 56px;
}

/* The four impact statements, which sat in their own `.impact-bar` section on
   --paper below the fold until 3 August 2026 and now close the hero in place of
   the old 20+/30+/Award-winning stat row.

   The move is a light surface to a dark one, so the two colours both had to
   change: the text was --ink and the number --steel, and neither survives on
   the scrim. See the contrast note on .impact-stmt__text. */
.hero__impact {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  border-top: 1px solid rgba(239,236,228,0.18);
  padding-top: 28px;
}

@media (min-width: 720px) {
  .hero__impact { grid-template-columns: repeat(2, 1fr); gap: 28px 32px; }
}

@media (min-width: 1080px) {
  .hero__impact { grid-template-columns: repeat(4, 1fr); gap: 32px; }
}

/* Button variants used in hero */
.btn--saffron {
  background: var(--saffron);
  color: var(--ink);
  border: none;
  border-radius: 2px;
  padding: 14px 24px;
  font-size: 14px;
}

.btn--saffron:hover {
  background: var(--ink);
  color: var(--saffron);
}

.btn--ghost-dark {
  background: transparent;
  color: var(--paper);
  border: 1px solid rgba(239,236,228,0.4);
  border-radius: 2px;
  padding: 14px 24px;
  font-size: 14px;
}

.btn--ghost-dark:hover {
  background: var(--paper);
  color: var(--ink);
}

/* ============ IMPACT STATEMENTS (in the hero) ============ */
.impact-stmt {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-left: 18px;
  border-left: 2px solid var(--saffron);
}

/* Was --steel (#5a6068), which measures 1.78:1 against the worst-case scrim here
   — a light-surface colour that would have been all but invisible. This is the
   same treatment the stat labels it replaces carried, and measures 5.19:1. */
.impact-stmt__num {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(239,236,228,0.66);
  font-weight: 500;
}

/* Was --ink, which measures 1.62:1 here — near-black on near-black once it moved
   onto the scrim.

   Measured the way the hero scrim comment above asks for: against the brightest
   pixels of twelve frames of hero-video.mp4, sampled across the vertical band
   this text occupies, composited video-at-0.5 over --ink and then under the
   scrim gradient. Worst case is 9.58:1, far clear of the 4.58:1 eyebrow that
   binds the hero.

   The band is 0.70–0.90 of hero height on desktop but 0.53–0.94 on mobile, where
   the statements stack into four rows and the hero grows to ~1290px — so the
   sample runs 0.50–0.95, and the worst case does in fact land at 0.52, up in the
   lighter part of the gradient. Re-measure over the mobile band, not the desktop
   one, if this block moves or the scrim changes.

   Full --paper rather than the 0.66 alpha of the number above, because this is
   14.5px body copy being read, not a label being glanced at. */
.impact-stmt__text {
  font-family: var(--body);
  font-weight: 400;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--paper);
  letter-spacing: -0.005em;
}

/* ============ SECTION SHELL ============ */
.section {
  padding: 96px 0 88px;
  position: relative;
}

@media (max-width: 720px) {
  .section { padding: 64px 0 56px; }
}

/* The research cards sat 184px clear of the approach section below them — 88px
   of #research bottom padding plus 96px of #approach top padding — which read as
   a hole rather than a break. Halved to 92px on 3 August 2026.

   Scoped to these sections rather than applied to .section, because the same
   class sets the rhythm for the news section and Joel asked for this gap
   specifically. Mobile halves from 120px to 60px on the same split.

   The acronym section moved in between the two on 9 August 2026 and carries the
   matching halves of its own (see #acronym below), so both joins still come to
   92px and the rule below is unchanged. */
#research { padding-bottom: 44px; }
#approach { padding-top: 48px; }

@media (max-width: 720px) {
  #research { padding-bottom: 28px; }
  #approach { padding-top: 32px; }
}

.section--paper2 { background: var(--paper-2); }

.section__eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--steel);
  font-weight: 500;
  margin-bottom: 14px;
}

.section__title {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1.05;
  letter-spacing: -0.026em;
  margin-bottom: 8px;
}

.section__title em {
  font-style: normal;
  color: var(--saffron);
}

/* ============ RESEARCH FOCUS (photo cards, no colour wash) ============ */
/* 32px, down from 56px on 3 August 2026. The heading and the four cards are one
   thought — the heading names the research focus and the cards enumerate it —
   and 56px opened a gap wide enough that they read as separate blocks. */
.atlas-intro {
  margin-bottom: 32px;
  max-width: 880px;
}

.atlas-intro h2 {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(32px, 5vw, 56px);
  line-height: 1.02;
  letter-spacing: -0.03em;
  color: var(--ink);
}

/* The three highlighted terms alternate through the categorical accents, in the
   order the research lines carry them.

   The middle mark is --saffron at Joel's explicit instruction, 6 August 2026,
   after the contrast was measured and put to him: it is 1.88:1 on --paper and
   fails WCAG AA for text at any size. This is the one deliberate exception to
   the "saffron on dark surfaces only" rule in CLAUDE.md — a decision, not an
   oversight, so do not "fix" it back to a passing colour without asking him.
   The other two measure petrol 9.01:1 and canopy 8.31:1. */
.atlas-intro h2 em {
  font-style: normal;
}

.atlas-intro h2 .mark--petrol  { color: var(--petrol); }
.atlas-intro h2 .mark--saffron { color: var(--saffron); }
.atlas-intro h2 .mark--canopy  { color: var(--canopy); }

.atlas {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

@media (min-width: 720px) { .atlas { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .atlas { grid-template-columns: repeat(4, 1fr); gap: 16px; } }

.atlas-card {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform 0.25s, border-color 0.25s;
}

.atlas-card:hover { transform: translateY(-3px); border-color: var(--ink); }

.atlas-card__image {
  aspect-ratio: 4 / 3;
  position: relative;
  overflow: hidden;
  background: var(--ink);
}

.atlas-card__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}




.atlas-card__body {
  padding: 24px 22px;
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

.atlas-card__num {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  color: var(--steel);
  font-weight: 500;
  margin-bottom: 14px;
}

.atlas-card__title {
  font-family: var(--display);
  font-weight: 600;
  font-size: 19px;
  letter-spacing: -0.015em;
  line-height: 1.18;
  color: var(--ink);
  margin-bottom: 14px;
}

.atlas-card__body p {
  font-family: var(--body);
  font-weight: 300;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink-soft);
  margin-bottom: 20px;
  flex-grow: 1;
}

.atlas-card__link {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  border-bottom: 1.5px solid var(--saffron);
  padding-bottom: 3px;
  text-decoration: none;
}

/* ============ FULL-BLEED BAND ============ */
/* Edge to edge, outside .container. The photograph is 3.61:1 and stays at that
   ratio on desktop, because a panorama that has been cropped square is not a
   panorama. Below 720px that ratio would make a 375px-wide screen show a 104px
   sliver, so the band crops in to 2.2:1 — a centre crop, which keeps both
   pylons: they sit at 34% and 57% of the width, and 2.2:1 shows the middle 61%.
   Check that if the image is ever swapped. */
/* .bleed-band moved to styles.css on 11 August 2026 — the research page carries
   two of these bands now as well, and a component used on two pages does not
   belong in one page's stylesheet. */

/* ============ ACRONYM (the nine letters) ============ */
/* Moved here from the about page on 9 August 2026, along with that page's hero
   copy, which now introduces the letters in place of "FRONTERAS is more than an
   acronym." The copy was set for a full-bleed dark hero at up to 108px; it sits
   in a ~480px column on paper here, so the display sizes come down and the
   accent changes — see .acronym__title em below. */

/* Same 92px break the research cards were given above the approach section
   (see #research / #approach further up): the cards now sit above this instead,
   and this sits above approach, so both joins keep that rhythm. */
#acronym { padding-top: 48px; padding-bottom: 44px; }

@media (max-width: 720px) {
  #acronym { padding-top: 32px; padding-bottom: 28px; }
}

.acronym__grid {
  display: grid;
  grid-template-columns: 1fr 1.5fr;
  gap: 56px;
  align-items: start;
}

/* The "Why Fronteras?" jump lands lower in the viewport than the other five, so
   the bottom of the Puente Bioceánica band is still on screen above the
   heading — the photograph is the section's lead-in and arriving with it just
   off the top loses that. scroll-margin-top adds to the 142px scroll-padding
   above, so the section top lands at 142 + this.

   THERE IS A CEILING ON THIS NUMBER and it is not stylistic: section-nav.js
   marks a section current when its top edge is inside a band running from 142px
   to 45% of the viewport, which is 324px at 720px tall. Land the section below
   that and the click highlights nothing, which reads as the bar being broken.
   150 puts it at 292 with 32px in hand. Anything past ~180 breaks it. */
#acronym { scroll-margin-top: 150px; }

/* This column pins while the letters of the acronym scroll past it, so its
   offset has to clear everything sticky above it. That was the 73px header
   plus air; since 13 August 2026 it is the header plus the 46px section nav,
   and at the old 104px this column slid underneath the bar. */
.acronym__copy {
  max-width: 480px;
  position: sticky;
  top: 150px;
}

.acronym__title {
  font-family: var(--display);
  font-size: clamp(34px, 3.8vw, 54px);
  line-height: 1.0;
  letter-spacing: -0.028em;
  font-weight: 400;
  color: var(--ink);
  margin: 12px 0 18px;
  text-wrap: balance;
}
/* --saffron carried this word on the about page's dark hero (8.25:1 on --ink).
   On paper it measures 1.88:1 and fails AA at any size, so the light-surface
   blue takes it: --petrol is 9.01:1 on --paper. Do not repoint this to saffron
   to match the old page. */
.acronym__title em { font-style: italic; color: var(--petrol); }

.acronym__lead {
  font-family: var(--display);
  font-size: clamp(19px, 1.6vw, 22px);
  line-height: 1.4;
  color: var(--ink);
  margin-bottom: 20px;
}

.acronym__body {
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--steel);
}
.acronym__body em { font-style: italic; }
.acronym__body + .acronym__body { margin-top: 14px; }

/* --- Collective logo beside the letters ----------------------------------- */
/* The copy in this column runs shorter than the letters column, so the rest of
   it is empty paper. The collective's logo fills that, holding while the nine
   letters travel up past it and fading out as the section goes.

   NOT A WATERMARK, and that is the whole reason the rules below differ from the
   weave marks elsewhere on the site. brand-mark.png is a 512 square with an
   opaque --canopy ground (#0e4d3a to the corner — no alpha, no rounding), so
   the 0.30 opacity every weave ships at would render it as a pale sage block
   rather than as the logo. It sits at full strength and reads as a card. For
   the same reason there is no bottom mask: it dissolved the weave's
   already-fading edge, but on a hard-edged square it would look like a
   photograph cut off mid-way.

   It was favicon.png until 10 August 2026, which carries the "FRONTERAS
   Collective" wordmark under the weave. Joel asked for the wordmark off the
   logo everywhere it appears on the site, so this and the header/footer mark
   now share brand-mark.png — the weave alone, generated by
   tools/make-brand-images.py. favicon.png keeps the wordmark and stays the
   browser tab icon.

   It needs no sticky of its own — .acronym__copy above is already
   position: sticky, so the whole column holds and this rides along inside it.
   Do not make this element sticky as well, and note that the 1100px breakpoint
   turns the column static, which is why the mark is hidden at the same width.

   It is decorative and empty by design — the markup carries aria-hidden and no
   text. The logo's own wordmark repeats the collective's name, which the h2
   beside it already says, so nothing is lost to a screen reader.

   THE FADE. This is a scroll-driven CSS animation, no JavaScript: the site has
   exactly two scripts and this is not worth making it three. animation-timeline
   is Chromium and Safari 26+; Firefox does not have it yet. That is why the
   animation only takes opacity away from the element's own resting value — a
   browser without the timeline simply renders the logo steadily. Nothing is
   broken by the fallback; it just does not move. */
.acronym__mark {
  margin-top: 40px;
  /* Centred on the column, under the copy — NOT right-aligned. Square, because
     the artwork is; right-aligned, a hard-edged square reads as off balance
     against the paragraphs above, which fill the column. */
  margin-inline: auto;
  width: min(240px, 60%);
  aspect-ratio: 1;
  pointer-events: none;
  background-image: url('/assets/img/brand-mark.png');
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
}
@supports (animation-timeline: view()) {
  .acronym__mark {
    animation: acronym-mark-out linear both;
    animation-timeline: view();
    /* Full strength while the section enters and sits in frame, gone by the
       time its last letters have travelled up out of it. */
    animation-range: cover 30% cover 85%;
  }
  @keyframes acronym-mark-out {
    from { opacity: 1; }
    to   { opacity: 0; }
  }
}
/* A fade tied to scroll position is motion. Someone who has asked for less of
   it gets the steady logo instead. */
@media (prefers-reduced-motion: reduce) {
  .acronym__mark { animation: none; opacity: 1; }
}

.acronym__letters { display: flex; flex-direction: column; gap: 0; }

.acronym__row {
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: 20px;
  align-items: baseline;
  padding: 20px 0;
  border-top: 1px solid var(--rule);
}
.acronym__row:last-child { border-bottom: 1px solid var(--rule); }

.acronym__letter {
  font-family: var(--display);
  font-size: clamp(52px, 5.5vw, 76px);
  line-height: 0.85;
  letter-spacing: -0.03em;
  font-weight: 300;
  color: var(--petrol);
  opacity: 0.9;
}

.acronym__word {
  font-family: var(--display);
  font-size: clamp(22px, 2.2vw, 27px);
  line-height: 1.12;
  letter-spacing: -0.015em;
  font-weight: 500;
  color: var(--ink);
  margin-bottom: 10px;
}
/* The letter the acronym is drawing from, picked out inside the word itself. */
.acronym__word__lead { color: var(--petrol); }

.acronym__desc {
  font-size: 15px;
  line-height: 1.62;
  color: var(--steel);
  max-width: 58ch;
}

/* One column below 1100px. The letters run full width and there is no empty
   half left for the mark to occupy, so it goes. */
@media (max-width: 1100px) {
  .acronym__grid { grid-template-columns: 1fr; gap: 40px; }
  .acronym__copy { position: static; max-width: 640px; }
  .acronym__mark { display: none; }
}

@media (max-width: 720px) {
  .acronym__row { grid-template-columns: 46px 1fr; gap: 14px; }
}

/* ============ APPROACH (replaces visual language) ============ */
.approach-head {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  margin-bottom: 48px;
  align-items: end;
}

@media (min-width: 720px) {
  .approach-head { grid-template-columns: minmax(0, 2fr) minmax(0, 1.3fr); gap: 48px; }
}

.approach-intro {
  font-family: var(--body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 460px;
}

.approach {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  align-items: center;
}

@media (min-width: 880px) {
  .approach { grid-template-columns: 1fr 1fr; gap: 64px; }
}

.approach__image {
  aspect-ratio: 4 / 5;
  background: var(--ink);
  border-radius: 4px;
  position: relative;
  overflow: hidden;
}

.approach__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}


/* ============ THE ANIMATED HEADING ============ */
.approach__trans {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(26px, 3.2vw, 38px);
  line-height: 1.05;
  letter-spacing: -0.026em;
  color: var(--ink);
  margin-bottom: 18px;
}

/* ---------- The animated heading ----------
   Research page → collective page → here, 11 August 2026. It sits above the
   research statement now, as display type introducing the pull quote rather
   than a section heading, so it is set at the quote's scale and not the
   section title's.
   "Trans" holds still while the suffix cycles disciplinarity → lation →
   formation. Behaviour lives in assets/js/trans-animation.js.

   Type is inherited from .section-title rather than set here. The demo this
   came from carried its own Arial at weight 850 and -0.065em tracking; kept,
   that would have made this the only heading on the site in a different face,
   weight and rhythm from every other h2. Only line-height is overridden, back
   to 1, because the window's vertical nudge below was calibrated against it. */
.trans-heading { display: block; }

.trans-anim {
  display: inline-flex;
  align-items: baseline;
  white-space: nowrap;
  max-width: 100%;
  line-height: 1;
}

.trans-anim__stem { flex: 0 0 auto; }

/* The clip. Its width is animated in JS to the measured width of each suffix,
   which is what makes the word grow and shrink rather than jump. 1.3em of
   height and line-height leave room for the descender in "disciplinarity".

   No baseline nudge. The source demo carried transform: translateY(0.06em)
   here, tuned to Arial's metrics; against IBM Plex Sans that is not a
   correction but the error itself. Measured 6 August 2026 with a zero-height
   baseline marker in the stem and in each suffix: all three sat exactly 0.06em
   low, matching the nudge, and align to the stem with it gone. If the face or
   line-height ever changes, re-measure rather than eyeball it. */
.trans-anim__window {
  position: relative;
  display: inline-block;
  height: 1.3em;
  overflow: hidden;
  vertical-align: baseline;
  line-height: 1.3;
  transition: width 520ms cubic-bezier(0.22, 1, 0.36, 1);
}

.trans-anim__track {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  will-change: transform;
  transition: transform 700ms cubic-bezier(0.22, 1, 0.36, 1);
}

.trans-anim__suffix {
  display: block;
  height: 1.3em;
  line-height: 1.3;
  white-space: nowrap;
}

/* Required by WCAG 2.2.2 — motion that starts on its own and runs past five
   seconds needs a way to stop it. Rendered hidden and unhidden by JS, so it
   never shows for a reader who has no animation to pause. */
/* The pause control, revealed on hover. It is required by WCAG 2.2.2 — see the
   note at the top of assets/js/trans-animation.js — and Joel wanted it out of
   the way rather than gone.

   :focus-visible is listed alongside :hover and is the load-bearing half. The
   button keeps its place in the flow and in the tab order at all times; only
   opacity moves, so nothing shifts when it appears and a keyboard user reaches
   it in sequence and sees it the moment it takes focus. Revealing on hover
   alone would leave the page looking compliant while the people the criterion
   is written for could not operate it.

   pointer-events are left alone deliberately: the button sits inside the
   element that reveals it, so a pointer close enough to click it has already
   made it visible. */
.trans-anim__toggle {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--steel);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 4px 12px;
  margin-bottom: 18px;
  cursor: pointer;
  opacity: 0;
  transition: opacity .18s ease, border-color .18s ease, color .18s ease;
}
.approach__trans-wrap:hover .trans-anim__toggle,
.approach__trans-wrap:focus-within .trans-anim__toggle,
.trans-anim__toggle:focus-visible {
  opacity: 1;
}
.trans-anim__toggle:hover {
  border-color: var(--rule-strong);
  color: var(--ink);
}
.trans-anim__toggle:focus-visible {
  outline: 2px solid var(--petrol);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .trans-anim__toggle { transition: none; }
}

@media (prefers-reduced-motion: reduce) {
  .trans-anim__window,
  .trans-anim__track {
    transition-duration: 0.01ms !important;
  }
}

.approach__quote {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(22px, 2.6vw, 30px);
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--petrol);
  margin-bottom: 24px;
  padding-left: 20px;
  border-left: 2px solid var(--petrol);
}

.approach__attr {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--steel);
  font-weight: 500;
  margin-bottom: 28px;
}

.approach__body {
  font-family: var(--body);
  font-weight: 300;
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--ink-soft);
  margin-bottom: 24px;
  max-width: 480px;
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
  padding: 11px 20px;
  font-size: 13px;
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  transition: background 0.2s, color 0.2s, border-color 0.2s;
}

.btn--ghost:hover {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

/* ============ FIELD NOTES (smaller 3-up cards) ============ */
.notes-head {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  margin-bottom: 40px;
  align-items: end;
}

@media (min-width: 720px) {
  .notes-head { grid-template-columns: 1fr auto; gap: 32px; }
}

.notes {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

@media (min-width: 720px) {
  .notes { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
}

.note {
  display: flex;
  gap: 16px;
  padding: 20px;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 4px;
  text-decoration: none;
  transition: border-color 0.2s, background 0.2s, transform 0.2s;
}

.note:hover { border-color: var(--ink); transform: translateY(-2px); }

.note__thumb {
  width: 86px;
  height: 86px;
  flex-shrink: 0;
  border-radius: 2px;
  overflow: hidden;
  background: var(--paper-3);
  position: relative;
}

.note__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.note__thumb__dot {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1.5px solid rgba(255,255,255,0.6);
  z-index: 2;
}

.note__content { display: flex; flex-direction: column; gap: 8px; min-width: 0; flex-grow: 1; }

.note__meta {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--steel);
  font-weight: 500;
}

.note__title {
  font-family: var(--display);
  font-weight: 500;
  font-size: 15px;
  line-height: 1.25;
  letter-spacing: -0.012em;
  color: var(--ink);
}

.note__excerpt {
  font-family: var(--body);
  font-weight: 300;
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-soft);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ============ LET'S CONNECT ============ */
/* Moved off the about page on 10 August 2026, where it sat on lets-connect.jpg
   under a measured dark scrim. The photograph and that scrim came out the same
   day at Joel's instruction.

   The ground is --paper-3, one step down from the --paper-2 of the Radio So'o
   section directly above, so the two read as separate sections without a rule
   between them. It was briefly --paper-2 to match the approach section, which
   put it on the same ground as Radio So'o and merged the pair.

   --paper-3 is the ground publications.css explicitly REJECTED for .p-themes,
   on the grounds that it puts --steel at exactly 4.50:1 with nothing spare.
   That objection does not reach this section: --steel is used only for the card
   body copy, and the cards carry their own --paper fill, where it measures
   5.38:1. Nothing on the paper-3 ground itself is set in --steel — and if
   anything ever is, that 4.50 is the number to answer for.

   Every colour flipped from a dark-surface token to its light-surface partner
   when the photograph went. Measured on the two grounds this section has:

     ground --paper-3 #ddd9cd      card --paper #efece4
       eyebrow  --petrol    7.53     num    --petrol  9.01
       title    --ink      12.96     title  --ink    15.50
       intro    --ink-soft  9.26     body   --steel   5.38
                                     link   --petrol  9.01

   --saffron is not available to any of them: 1.55:1 on the ground and 1.88:1 on
   the card. It carried the eyebrow and the card link hover on the dark version
   and would have survived the move invisibly. */
.connect {
  padding: 96px 0;
  background: var(--paper-3);
}

.connect .section-title { color: var(--ink); }

.connect__head {
  display: grid;
  grid-template-columns: 1fr 1.5fr;
  gap: 56px;
  align-items: end;
  margin-bottom: 44px;
}
.connect__head .section-title { margin-top: 12px; }
.connect__intro {
  font-size: 16px;
  line-height: 1.62;
  color: var(--ink-soft);
  max-width: 58ch;
}
.connect__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}
/* --paper on --paper-3, so the card is a step lighter than its ground where the
   research focus section's cards are level with theirs. --rule-strong rather
   than --rule for the border: against paper-3 the lighter rule is 1.19 and all
   but gone, and the card's own fill is only carrying 1.2 of separation. The
   dark version was deliberately near-opaque so the photograph could not vary
   underneath the body copy; with no photograph there is nothing to hide, so
   this is a flat surface. */
.connect__card {
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-card-lg);
  background: var(--paper);
  padding: 30px 26px 26px;
  display: flex; flex-direction: column; gap: 14px;
  transition: border-color .2s ease, transform .2s ease, background .2s ease;
}
.connect__card:hover {
  border-color: var(--petrol);
  background: #f5f2ea;
  transform: translateY(-2px);
}
.connect__card__num {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  color: var(--petrol);
}
.connect__card__title {
  font-family: var(--display);
  font-size: 21px;
  line-height: 1.18;
  letter-spacing: -0.012em;
  font-weight: 500;
  color: var(--ink);
}
.connect__card p {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--steel);
  flex: 1;
}
.connect__card__link {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--petrol);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
  align-self: flex-start;
}
/* Was --saffron, 1.88:1 here. The darker petrol the site uses for light-surface
   hovers throughout. */
.connect__card__link:hover { color: #16334a; }

/* ---------- CONTACT FORM ---------- */

@media (max-width: 1100px) {
  .connect__head { grid-template-columns: 1fr; gap: 32px; }
  .connect__grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 720px) {
  .connect { padding: 64px 0; }
  .connect__grid { grid-template-columns: 1fr; }
}
