/* RESEARCH PAGE — local styles. Prefix: r- */

/* Single column and dark since 12 August 2026. The two-column grid that was
   here — .r-hero__grid, .r-hero__left, .r-hero__lead, .r-hero__body and the
   .r-atlas-tile video frame — went with it: the two paragraphs were deleted,
   the approaches moved in below the headline, and the video became the
   full-bleed band under this section.

   It carries a photograph now, so every colour in here changed sides. --ink on
   --paper became --paper on a scrimmed image, and the two accents had to swap
   for their dark-surface counterparts. See the scrim note below — those numbers
   are measured off the composited pixels, not off a token pair. */
.r-hero {
  background: var(--ink);
  color: var(--paper);
  padding: 96px 0 72px;
  position: relative;
  overflow: hidden;
  isolation: isolate;     /* keeps the scrim under the text without z-index on everything */
}
.r-hero__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
}
.r-hero__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Top, not centre. At a 1280px viewport the hero box is 1280x722 and this
     image scales to 1280x853 — 131px of vertical slack and NONE horizontal, so
     the horizontal half of this property does nothing at desktop width and only
     bites on narrow viewports. (A first pass set it to 42% for reasons that
     could not have applied. Measured since.)

     The vertical half does bite, and the top of the frame measured best of the
     three positions tested: headline 7.40:1 against --paper at top, 7.29 at
     35%, 7.41 centred, with the top also showing the most of the picture. */
  object-position: 50% 0%;
  display: block;
}
/* THE SCRIM, and why it is this dark.
   The photograph is mid-tone canopy from edge to edge with no quiet corner to
   put text in, so the text cannot be placed around it — it has to sit over it,
   and the scrim is therefore doing the entire contrast job.

   Lightened 19 August 2026 from 0.86/0.74/0.88, after readers said the picture
   was hard to make out. The gradient SHAPE is untouched — every stop moved by
   the same 0.04 — because the shape was fitted to this frame and only the
   overall weight was at issue.

   THE OLD NOTE HERE NAMED THE WRONG BINDING CONSTRAINT, and the correction is
   the whole reason this was possible. It said --petrol-lift on the headline's
   <em> was what pinned the scrim. Measuring every text node in the hero against
   the composited pixels — not just the four the note listed — found three
   things tighter than the <em>, all of them small text needing 4.5 rather than
   a headline needing 3.0:

     .r-commit__more   10.5px  rgba(243,235,221,.62)   5.16:1  ratio-to-req 1.15
     .r-commit__sym    12px    --saffron               5.30:1               1.18
     .eyebrow          11px    --saffron               5.63:1               1.25
     headline <em>     64px    --petrol-lift           3.94:1               1.31

   So the <em> had the MOST headroom of the four, not the least. What actually
   unlocked this was lifting the two small saffron spans to --saffron-lift and
   taking .r-commit__more from .62 to .72 alpha; only after both does the <em>
   finally become binding, which is where the old note assumed it already was.

   Measured on the composited pixels behind the real text boxes, worst-case
   pixel, at BOTH widths — 1280x720 and 375x812. Desktop shown:

     headline    --paper         8.55:1   AA yes, AAA yes (large text)
     headline    --petrol-lift   3.38:1   AA yes for large text (3:1) — binding
     eyebrow     --saffron-lift  5.98:1   AA yes
     .sym        --saffron-lift  5.36:1   AA yes
     .more       .72 alpha       5.71:1   AA yes
     .charter    .82 alpha       5.51:1   AA yes

   The <em> at 3.38 is now the tightest thing here and it is large text only —
   at 64px it clears the 3:1 bar, and it would fail the 4.5 one. Do not shrink
   .r-hero__title below 24px without re-measuring, and do not lighten this scrim
   further without giving the <em> a lighter colour, which is finally the true
   statement the old note made prematurely.

   The picture is made legible under this by contrast, not by less scrim — the
   source carries a 1.35 boost from tools/make-research-hero.py for exactly that
   reason, and the reasoning with its measurements is in that docstring.

   CLAUDE.md warns against reintroducing an overlay on the chaco-road footage.
   That warning is about the video, which never had text on it and lost its
   colour to a scrim for nothing. This is the opposite case: text over a
   photograph, where the scrim is the accessibility fix. */
.r-hero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      rgba(10, 13, 18, 0.82) 0%,
      rgba(10, 13, 18, 0.70) 42%,
      rgba(10, 13, 18, 0.84) 100%);
}
/* --saffron-lift, not --saffron: 11px is small text and needs 4.5:1. Under the
   lightened scrim the base token lands under that; see the note above. */
.r-hero__inner { position: relative; }
/* --saffron-lift, not --saffron: 11px is small text and needs 4.5:1. Under the
   lightened scrim the base token lands under that; see the note above. */
.r-hero__eyebrow { margin-bottom: 22px; color: var(--saffron-lift); }
/* Bigger than it could ever be in the old two-column hero — nothing sits beside
   it now, and it no longer sets the height of a video tile, which is what the
   old note here was about: at clamp(…, 110px) a 89-character headline ran to
   nine lines and stretched the tile (align-items: stretch) into a portrait box
   that cropped the cattle truck out of the shot. That coupling is gone.

   24ch is the constraint that matters. The headline is 73 characters, so it
   sets to three lines at any size in the clamp; let it run the full container
   and it drops to two very long ones. */
.r-hero__title {
  font-family: var(--display);
  font-size: clamp(36px, 5vw, 72px);
  line-height: 1.03;
  letter-spacing: -0.026em;
  font-weight: 400;
  color: var(--paper);
  max-width: 24ch;
  margin-bottom: 0;
  text-wrap: balance;
}
/* No accent word here. The headline's <em> ("just futures.") was --petrol-lift
   until 22 August 2026, when Joel asked for every hero headline to read in plain
   --paper with no colour and no italics. Note what that does to the scrim
   arithmetic above: the <em> at 3.38:1 was the tightest thing in this hero once
   the small text had been lifted, and it is no longer here. The binding
   constraint reverts to .r-commit__more at 5.71:1. The scrim was NOT touched —
   re-measure before spending that room. */

/* THE CHARTER — the approaches, in the hero.
   Was .r-methods / .r-methods__notebook / .r-commits at the foot of the page: a
   boxed section on --paper-2 with a 2×2 grid inside it. Here it is not a box.
   It reads as the second half of the hero, separated from the headline by a
   rule rather than by a panel, because a card floating in a hero looks like an
   advertisement for the page it is already on.

   The head that sat here — an "Approaches" eyebrow and a second display
   heading — was cut on 12 August 2026. .r-charter__head and .r-charter__title
   went with it. Only the intro line remains, and it leads straight into the
   cards. */
.r-charter {
  margin-top: 52px;
  padding-top: 36px;
  border-top: 1px solid rgba(243, 235, 221, 0.22);
}
.r-charter__body {
  font-size: 15px;
  line-height: 1.6;
  color: rgba(243, 235, 221, 0.82);
  margin-bottom: 32px;
  max-width: 52ch;
}
/* Four across on one hairline. Each cell draws its own border-top rather than
   the container drawing one line, so the rule breaks at the gaps and reads as
   four columns of a ledger instead of one underscored block.
   The <dialog>s are grid children too — display:none until opened, so they take
   no track, but `gap` would still count them if they were laid out. They are
   not, because a closed dialog is display:none. */
.r-charter__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0 40px;
}

/* THE CHACO ROAD BAND.
   The shared .bleed-band in styles.css sizes an <img>; this is the only band on
   the site holding a <video>, so the ratio rules there do not reach it and it
   carries its own.

   16:9, which is the source ratio — the video is not cropped at all, and this
   is the second attempt. The first cropped it to 2.5:1, which suits the wide
   reveal and destroys the overhead: from directly above, the truck lies ALONG
   the road and its long axis is vertical in frame, so a horizontal band cuts
   its ends off. Measured at 2:1 across t=4..42, it ran off an edge in four
   frames of six. Joel asked for the overhead to be legible, so the frame is
   whole and the band is as tall as the footage.

   No mobile override for the same reason — a squarer crop on a phone would put
   the ends of the truck back outside the frame. */
.bleed-band--video { margin: 0; }
.bleed-band__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center;
  background: #2a3027;   /* the footage's own dark, before the first frame paints */
}

.r-section-head {
  display: grid;
  grid-template-columns: 1fr 1.5fr;
  gap: 56px;
  align-items: end;
  margin-bottom: 48px;
}
.r-section-head__title { max-width: 20ch; }
/* --ink-soft, not --steel. Only .r-lines uses this class.

   THE REASON FOR IT CHANGED ON 25 AUGUST 2026 and the rule stays. This
   paragraph used to sit over a woven watermark on .r-lines, which is why it was
   not --steel: --steel clears AA on bare paper only, at 5.38:1 with almost
   nothing spare, and over the watermarked ground it dropped to 3.30-3.86:1 —
   the exact failure Joel caught on the collective page. Joel asked for every
   watermark off the site, so the ground under this paragraph is now bare
   --paper and --steel would in fact pass here. It was left at --ink-soft
   (11.07:1) anyway, and for a different reason than it was set: the four line
   cards this paragraph introduces carry --steel bodies, and a section intro the
   same weight as the cards below it flattens the hierarchy. What was a contrast
   requirement is now a typographic one. Do not "simplify" it to --steel to
   match the cards — that is the change this comment exists to argue against. */
.r-section-head__body {
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 56ch;
}

.r-lines {
  position: relative;
  overflow: hidden;
  padding: 96px 0;
  background: var(--paper);
}

/* The woven corner mark that sat top right here was REMOVED on 25 August 2026,
   when Joel asked for every watermark off the site. It was weave-corner.svg at
   0.30 (0.18 below 1100px) in a square box anchored top right, with a mask
   dissolving it along the bottom edge; the collective page's .atlas carried the
   same asset and lost it in the same change.

   .r-lines keeps `position: relative; overflow: hidden` above and this z-index
   on the container. Both were there for the mark, and both are now doing
   nothing — left in place rather than stripped, because .r-lines is one of the
   sections listed in the overlay-host block in styles.css and a section that is
   a positioned, clipping stacking context is the state the rest of this file
   assumes. Removing them is a separate change with its own testing. */
.r-lines .container {
  position: relative;
  z-index: 1;
}
.r-lines__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin-top: 8px;
}
/* The padding moved off the card and onto .r-line__content so the photograph can
   run edge to edge. overflow: hidden is what clips it to the rounded corner. */
.r-line {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-card-lg);
  overflow: hidden;
  display: flex; flex-direction: column;
  min-height: 360px;
  transition: transform .2s ease, box-shadow .2s ease;
  position: relative;
}

/* A slice of the same photograph the homepage uses for this line — same file,
   same alt text, pulled from index.njk so the two pages cannot drift apart.

   The homepage card is this exact construction: an image band above a body.
   Full colour, no scrim — nothing sits on top of it.

   230px, up from the first pass at 132px. At 132 the band showed only 23% of the
   square sources' height and each photograph read as an unplaceable detail. 230
   shows 40% of the square ones and 71% of the wide road frame, which is what
   brings the sky, the treeline and the horizon into shot. */
.r-line__image {
  height: 230px;
  flex-shrink: 0;
  overflow: hidden;
  background: var(--ink);
}
.r-line__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Per-photograph vertical framing. The subject of each frame sits at a different
   height, so a single object-position cannot serve all four — centre put the
   horizon out of shot on three of them.

   The band covers 39.7% of the square sources' height and 71% of the wide road
   frame. Two of these values are derived rather than eyeballed, which is why
   they are odd numbers:

   01 30%  Joel asked for sky at about a fifth of the band. The treeline was
           measured off the source by row brightness — it falls at 26% of the
           frame, not the ~14% it looks like — so the window starts at 18.1% and
           the sky lands at exactly 20% of the band. The flame sits below it,
           whole.
   02 22%  the canopy, with the assembly still filling the lower half.
   03  0%  the widest of the four, so the band already covers 71% of it —
           anchored top, which brings in the horizon and sky.
   04 75%  centred on the hand holding the pen, which sits at 65% of this frame.
           The window runs 45.2%-84.8%, so the headdress at 0-15% is out of shot
           and the map fills the band. An earlier pass tried to hold the
           headdress and the map together; they are too far apart for one band,
           and Joel chose the map.

   Re-derive rather than nudge if a photograph is ever replaced: the numbers
   depend on where the subject falls in that specific file. */
#line-01 .r-line__image img { object-position: center 30%; }
#line-02 .r-line__image img { object-position: center 22%; }
#line-03 .r-line__image img { object-position: center 0%; }
#line-04 .r-line__image img { object-position: center 75%; }

.r-line__content {
  padding: 24px 26px 26px;
  display: flex; flex-direction: column;
  gap: 18px;
  flex: 1;
}
.r-line:hover {
  transform: translateY(-3px);
  box-shadow: 0 22px 48px -28px rgba(48,39,27,0.22);
}
/* These are real links now, to the matching theme on the publications page. They
   were decorative spans with a hover state, which promised an affordance that
   did not exist. */
.r-line__arrow {
  width: 36px; height: 36px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--rule-strong);
  display: grid; place-items: center;
  color: var(--ink-soft);
  font-size: 14px;
  text-decoration: none;
  transition: background .2s, color .2s, border-color .2s;
}
.r-line:hover .r-line__arrow,
.r-line__arrow:hover {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.r-line__arrow:focus-visible {
  outline: 2px solid var(--petrol);
  outline-offset: 3px;
}

/* The hierarchy here was inverted. The category — the thing a reader is
   scanning for — was a 10.5px mono eyebrow in --saffron, which measures 1.88:1
   on --paper and is the failure CLAUDE.md warns about by name; the subordinate
   clause under it was 22px --ink at 15.50:1. So the eye went to the clause and
   the theme itself was both small and barely legible.

   Now: the index is a quiet mono label in --petrol (9.01:1), the category is the
   h3 at 25px --ink, and the clause drops to 14.5px --ink-soft. Size, weight and
   colour all point the same way. */
.r-line__num {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--petrol);
  margin-bottom: 9px;
}
.r-line__title {
  font-family: var(--display);
  font-size: 25px;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: balance;
}
.r-line__sub {
  font-size: 14.5px;
  line-height: 1.4;
  font-weight: 500;
  color: var(--ink-soft);
  margin-top: 10px;
}
.r-line__body {
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--steel);
}
/* Pills left, arrow bottom-right, per Joel. The arrow used to sit in a head row
   opposite the icon; with the icon gone and the photograph in its place, the
   foot is where it belongs. align-items: flex-end keeps it on the last line of
   pills rather than floating when they wrap to two rows. */
.r-line__foot {
  margin-top: auto;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
}
.r-line__tags {
  display: flex; flex-wrap: wrap; gap: 6px;
  min-width: 0;
}

.r-projects {
  background: var(--ink);
  color: var(--paper);
  padding: 96px 0;
  overflow: hidden;
}
/* The intro used to be a sticky left rail beside a single tall column of
   projects. It now runs horizontally across the top — title left, framing
   paragraph and legend right — matching .r-section-head elsewhere on this page,
   and the projects sit below it in two columns. */
/* One column since 11 August 2026. The framing paragraph and the state legend
   that filled the right-hand column were deleted, and leaving the grid at
   1fr 1.2fr stranded the title in the narrower half of an otherwise empty
   row. */
.r-projects__head {
  margin-bottom: 44px;
}
.r-projects__intro__title {
  font-family: var(--display);
  font-size: clamp(32px, 3.4vw, 46px);
  line-height: 1.05;
  letter-spacing: -0.018em;
  font-weight: 400;
  color: var(--paper);
  margin-bottom: 22px;
  text-wrap: balance;
}
/* .r-projects__head__aside, __intro__body and the __legend rules were deleted
   on 11 August 2026 with the markup they styled. The states are still explained
   under the map, beside the pins that use them. */

.r-projects__list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 18px;
  align-items: start;
}

.r-proj {
  padding: 26px 26px 24px;
  border-radius: var(--r-card-lg);
  border: 1px solid rgba(243,235,221,0.12);
  background: rgba(255,255,255,0.04);
  transition: background .2s, border-color .2s;
  position: relative;
}
.r-proj:hover {
  background: rgba(255,255,255,0.06);
  border-color: rgba(243,235,221,0.22);
}
/* The emblematic image, added 10 August 2026. It is prepended to the card and
   nothing below it moved: the index row, states, title, location, body, tags and
   link are all where they were.

   Full-bleed inside the card, so the negative margin has to match .r-proj's
   26px padding exactly — change one and change the other. 2:1 rather than 16:9
   because these cards are dense and a taller band takes the card over; the
   ratio is baked into the files by tools/make-card-images.py, and aspect-ratio
   here only reserves the space so nothing reflows as they load. */
.r-proj__image {
  margin: -26px -26px 20px;
  border-radius: var(--r-card-lg) var(--r-card-lg) 0 0;
  overflow: hidden;
  aspect-ratio: 2 / 1;
  background: rgba(255,255,255,0.03);
}
.r-proj__image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.r-proj__head {
  display: flex; gap: 16px; align-items: flex-start; justify-content: space-between;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.r-proj__index {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(243,235,221,0.5);
  margin-bottom: 10px;
  display: flex; align-items: center; gap: 10px;
}
/* The funder or period — Moore Foundation, NSF · 2021—2026, Since 2019. This
   used to live inside the status element and so was tangled up with the state
   colour, which is why a project could only ever show one state. It is plain
   metadata and now sits on its own. */
.r-proj__meta {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* 0.58, not the 0.5 this inherited from .r-proj__index. At 0.5 it measured
     exactly 4.50:1 on the card — AA to two decimal places and no further, which
     is a value that fails the moment anything shifts. 0.58 is 5.58:1. */
  color: rgba(243,235,221,0.58);
}

/* State is a set, not a single value: a project can be long-term and active at
   once, or emergent and active. It was previously a modifier class on the
   article, which by construction allowed only one. Now each card renders its
   own row of labelled tags.

   Dot carries the colour, label stays neutral — the same construction as the
   legend above. With up to two tags side by side, colouring the words as well
   would put three accent colours in one line and make the row shout. The label
   already names the state, so the colour is reinforcement rather than the only
   channel. */
.r-proj__states {
  display: flex; flex-wrap: wrap; gap: 8px 14px;
  margin-bottom: 14px;
}
.r-proj__state {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(243,235,221,0.72);
}
.r-proj__state__dot {
  width: 7px; height: 7px; border-radius: 50%;
  flex-shrink: 0;
}
.r-proj__state--active   .r-proj__state__dot { background: var(--saffron); }
.r-proj__state--emerging .r-proj__state__dot { background: var(--canopy-lift); }
.r-proj__state--longterm .r-proj__state__dot { background: var(--petrol-lift); }
.r-proj__title {
  font-family: var(--display);
  font-size: clamp(24px, 2.2vw, 30px);
  line-height: 1.1;
  letter-spacing: -0.018em;
  font-weight: 400;
  color: var(--paper);
  flex: 1;
  min-width: 260px;
}
.r-proj__location {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 12px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(243,235,221,0.18);
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(243,235,221,0.78);
  white-space: nowrap;
}
.r-proj__location svg { color: var(--saffron); }
/* The title is the dialog trigger. A real <button> wrapping the text rather
   than a click handler on the card alone, so the interaction is reachable by
   keyboard and announced as opening a dialog. Styled to inherit completely —
   it has to read as the heading it is, not as a control. */
.r-proj__expand {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  cursor: pointer;
}
.r-proj__expand:focus-visible { outline: 2px solid var(--saffron); outline-offset: 3px; }
/* The whole card is clickable, so the affordance belongs to the card, not just
   to the title — underline on card hover as well as on the button's own. */
.r-proj:hover .r-proj__expand,
.r-proj__expand:hover {
  text-decoration: underline;
  text-decoration-color: var(--saffron);
  text-underline-offset: 4px;
}
.r-proj { cursor: pointer; }
/* Anything genuinely clickable inside the card keeps its own pointer — those
   escape the card handler in peer-cards.js. */
.r-proj a { cursor: pointer; }

/* ---- Project dialog ------------------------------------------------------
   The body paragraph, moved off the card on 12 August 2026. Mirrors
   .c-peer-modal on the collective page rather than sharing it: that lives in
   pages/collective.css, which does not load here, and one modal is not worth
   promoting to styles.css for every page to carry. If a third page grows one,
   promote it then. */
.r-modal {
  width: min(620px, calc(100vw - 40px));
  max-height: calc(100vh - 80px);
  padding: 0;
  border: 1px solid rgba(243,235,221,0.16);
  border-radius: var(--r-card-lg);
  background: #171c24;
  color: var(--paper);
  overflow: auto;
  /* The FLIP transition scales the whole dialog, so the origin has to be the
     centre for the movement to read as travel rather than stretch. */
  transform-origin: center center;
}
.r-modal::backdrop {
  background: rgba(10, 13, 18, 0.72);
  backdrop-filter: blur(3px);
}
.r-modal__inner { padding: 32px; position: relative; }
.r-modal__close {
  position: absolute;
  top: 16px; right: 18px;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1px solid rgba(243,235,221,0.24);
  background: none;
  color: inherit;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background .18s ease, border-color .18s ease;
}
.r-modal__close:hover { background: rgba(255,255,255,0.08); }
.r-modal__close:focus-visible { outline: 2px solid var(--petrol-lift); outline-offset: 2px; }
.r-modal__title {
  font-family: var(--display);
  font-size: clamp(21px, 2vw, 26px);
  line-height: 1.15;
  letter-spacing: -0.018em;
  font-weight: 400;
  color: var(--paper);
  margin-bottom: 16px;
  padding-right: 44px;
}
.r-modal__body {
  font-size: 15px;
  line-height: 1.65;
  color: rgba(243,235,221,0.82);
}

/* .r-proj__body was here. The card's paragraph moved into the dialog on
   12 August 2026 and the class is rendered nowhere, so the rule went with it
   rather than sitting as dead code — see .r-modal__body above. */
.r-proj__foot {
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 12px;
  padding-top: 16px;
  border-top: 1px solid rgba(243,235,221,0.1);
}
.r-proj__tags { display: flex; flex-wrap: wrap; gap: 8px; }
/* Con Territorio carries two: its publications and the project's own site. */
.r-proj__links { display: flex; flex-wrap: wrap; gap: 8px 20px; }
.r-proj__link {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--saffron);
  display: inline-flex; align-items: center; gap: 8px;
  text-decoration: none;
}
.r-proj__link:hover { color: var(--paper); }

/* The commitments. All that survives of the approaches section that sat at the
   foot of the page — .r-methods, .r-methods__notebook, .r-methods__head and
   .r-commits were deleted on 12 August 2026 along with the markup they styled,
   when the content moved into the hero.

   .r-commit__body went too, and that one is not a deletion: the paragraphs live
   in the dialogs now and are styled by .r-modal__body. Measured at 375x812 by
   restoring the paragraphs in the rendered page: 1.14 screens open against 0.79
   collapsed. A third of a screen, which is worth having but is not the reason —
   the reason is that four paragraphs are a dull way to open a page.

   The glyph sat beside the title on a 36px track when these were 2×2 in a
   half-width box. Above the title instead: at a quarter of the container that
   track cost a fifth of the measure.

   It is a number now, not a glyph — 17 August 2026, at Joel's instruction: four
   shapes (◐ ◇ ◆ ○) said nothing about the order, and the four principles are
   introduced as four. Zero-padded to match .r-line__num and .p-theme__num,
   which is the site's numbering everywhere else. Still aria-hidden: the four
   cards are already in document order, and the class name stays .r-commit__sym
   because it is the same slot doing the same job. */
.r-commit {
  padding: 18px 0 24px;
  border-top: 1px solid rgba(243, 235, 221, 0.22);
  cursor: pointer;
}
/* --petrol is 1.72:1 on a dark ground and unusable; --saffron is 8.25:1 there.
   This is the exact inverse of the light-surface rule — the glyphs were petrol
   while this section sat on paper, and both readings are correct for their own
   ground. */
/* --saffron-lift since 19 August 2026, not plain --saffron. 12px is small text
   and needs 4.5:1; under the lightened hero scrim the base token measured 4.51
   at the old weight and would have gone under it. See the scrim note at the top
   of this file — this span was one of the three things found to be tighter than
   the headline's <em>, which that note used to call the binding constraint. */
.r-commit__sym {
  display: block;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.12em;
  color: var(--saffron-lift);
  margin-bottom: 14px;
}
.r-commit__title {
  font-family: var(--display);
  font-size: 17px;
  line-height: 1.25;
  font-weight: 400;
  color: var(--paper);
  margin-bottom: 0;
}
/* Same construction as .r-proj__expand below: a button that inherits the
   heading's type so the heading is the control, rather than a separate link
   under it. */
.r-commit__expand {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  cursor: pointer;
}
.r-commit__expand:focus-visible { outline: 2px solid var(--saffron); outline-offset: 3px; }
.r-commit:hover .r-commit__expand,
.r-commit__expand:hover {
  text-decoration: underline;
  text-decoration-color: var(--saffron);
  text-underline-offset: 4px;
}
/* The affordance. Four titles and nothing else gives no sign that there is more
   behind them, and the cards carry no tags or links to imply it the way the
   project cards do. aria-hidden because the button already announces itself as
   opening a dialog. */
/* .72 alpha since 19 August 2026, up from .62. At 10.5px this is the SMALLEST
   text anywhere in the hero, and measuring found it — not the headline's <em> —
   was the single tightest ratio in the whole section at 5.16:1 against a 4.5
   bar. It is what capped the scrim lightening at -0.023; at .72 the cap roughly
   doubles to -0.045. Anything below about .70 puts the cap back. */
.r-commit__more {
  display: block;
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(243, 235, 221, 0.72);
}
/* --saffron-lift for the same reason as .r-commit__sym: 10.5px is small text. */
.r-commit:hover .r-commit__more { color: var(--saffron-lift); }

/* =========================================================
   THE RESEARCH ATLAS  (.r-map)
   =========================================================
   There used to be a warning here not to confuse this with .r-atlas-tile, the
   hero's video frame. That class is gone as of 12 August 2026, so .r-map is now
   the only "atlas" on the page.
   This is the map, and it sits directly above .r-projects — the two are one
   instrument, which is why this section carries no bottom padding and lets the
   projects section's own top padding do the spacing.

   Every colour below is measured against --ink (#11151c), since that is what
   the whole section sits on:
     --saffron            8.25:1   project pins, the P/nn references
     --petrol-lift        8.30:1   the equator
     paper at 0.6         6.18:1   the SVG's two labels, the key's quieter text
     paper at 0.8        10.16:1   site names
   The land fill is paper at 0.07, which is 1.18:1 against the ink — it is a
   surface, not text, and the saffron pins measure 7.01:1 on top of it. */
.r-map {
  background: var(--ink);
  color: var(--paper);
  padding: 96px 0 0;
  overflow: hidden;
}
.r-map__head { max-width: 760px; margin-bottom: 44px; }
.r-map__title {
  font-family: var(--display);
  font-size: clamp(28px, 3.4vw, 42px);
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0 0 18px;
}
.r-map__body {
  font-size: 16px;
  line-height: 1.65;
  color: rgba(243,235,221,0.8);
  margin: 0;
}

.r-map__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: 48px;
  align-items: start;
}

.r-map__figure { margin: 0; }
.r-map__svg {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid rgba(243,235,221,0.12);
  border-radius: var(--r-card-lg);
  background: rgba(255,255,255,0.02);
}

.r-map__grat line { stroke: rgba(243,235,221,0.05); stroke-width: 1; }
.r-map__equator {
  stroke: var(--petrol-lift);
  stroke-opacity: 0.3;
  stroke-width: 1;
  stroke-dasharray: 3 5;
}
.r-map__equator-label,
.r-map__inset-label,
.r-map__ocean-label {
  font-family: var(--mono);
  font-size: 8.5px;
  letter-spacing: 0.18em;
  fill: rgba(243,235,221,0.6);
}
.r-map__equator-label { fill: var(--petrol-lift); fill-opacity: 0.75; }

/* Set from its middle, because the bay it has to fit inside is only about ten
   units wider than the word is long. tools/make-atlas.py projects the anchor
   from the middle of the open water rather than from its left edge, so an
   anchor of `start` here would push the label onto the Burmese coast. */
.r-map__inset-label { text-anchor: middle; }

/* Ocean names. Quieter than the inset's own label and set in italic small caps'
   spirit — a map convention, and it keeps them from being read as another site
   label. paper at 0.42 is 3.62:1 on --ink, below AA, which is deliberate and
   safe here: the SVG is aria-hidden, these words carry no information the key
   does not, and at full strength they compete with fourteen pins. */
.r-map__ocean-label {
  fill: rgba(243,235,221,0.42);
  letter-spacing: 0.22em;
  font-size: 8px;
}

.r-map__land path {
  fill: rgba(243,235,221,0.09);
  stroke: rgba(243,235,221,0.2);
  stroke-width: 0.7;
  stroke-linejoin: round;
}
/* Opaque, not translucent. The inset sits over the Guianas, and at any
   transparency the South American coastline reads through it as if it were part
   of the Bay of Bengal. */
.r-map__inset > rect {
  fill: var(--ink);
  stroke: rgba(243,235,221,0.22);
  stroke-width: 1;
}

/* Pins. The halo is the hit target as well as the hover state — a 4.5px dot is
   too small to point at, so the transparent 12px circle around it does the
   catching. */
/* Pin state carries the same three colours as the project legend below, and
   they all sit on --ink: saffron 8.25:1, canopy-lift 8.15:1, petrol-lift
   8.30:1. The fourth tier, member, is paper at 0.55 (5.38:1) — deliberately
   quieter, because those sites are context rather than the collective's own
   research programme. */
.r-map__halo { fill-opacity: 0.12; transition: fill-opacity .18s; }
.r-map__dot {
  stroke: var(--ink);
  stroke-width: 1.2;
  transition: r .18s, fill-opacity .18s;
}
.r-map__pin--active   .r-map__dot, .r-map__pin--active   .r-map__halo { fill: var(--saffron); }
.r-map__pin--emerging .r-map__dot, .r-map__pin--emerging .r-map__halo { fill: var(--canopy-lift); }
.r-map__pin--longterm .r-map__dot, .r-map__pin--longterm .r-map__halo { fill: var(--petrol-lift); }
.r-map__pin--member   .r-map__dot { fill: var(--paper); }
/* The fifth tier, collaborator: a site worked by someone the collective
   collaborates with. Full-size dot and halo rather than the quieter member
   treatment — a collaborator's site is a peer category, not a footnote, and at
   one pin on a fourteen-pin map the smaller dot would simply be hard to find.
   --rose-lift is 8.25:1 on --ink; see the token in styles.css. */
.r-map__pin--collaborator .r-map__dot,
.r-map__pin--collaborator .r-map__halo { fill: var(--rose-lift); }

/* A site can be two states at once, the way a card can. The core is the first
   and the ring the second, in the order the card itself lists them — which is
   why the long-term sites read blue-cored with an active ring rather than the
   other way round. The alternative, splitting the dot into two half-circles,
   was rejected: at a 9px diameter it just reads as a muddy dot. */
.r-map__ring { fill: none; stroke-width: 1.8; transition: r .18s; }
.r-map__ring--active   { stroke: var(--saffron); }
.r-map__ring--emerging { stroke: var(--canopy-lift); }
.r-map__ring--longterm { stroke: var(--petrol-lift); }
.r-map__pin:hover .r-map__ring,
.r-map__pin:focus-visible .r-map__ring,
.r-map__pin.is-active .r-map__ring { r: 10.5; }

a.r-map__pin { cursor: pointer; }
.r-map__pin:hover .r-map__halo,
.r-map__pin:focus-visible .r-map__halo,
.r-map__pin.is-active .r-map__halo { fill-opacity: 0.32; }
.r-map__pin:hover .r-map__dot,
.r-map__pin:focus-visible .r-map__dot,
.r-map__pin.is-active .r-map__dot { r: 6.5; }
.r-map__pin--member:hover .r-map__dot,
.r-map__pin--member.is-active .r-map__dot { r: 5.2; }
a.r-map__pin:focus-visible { outline: none; }
a.r-map__pin:focus-visible .r-map__halo {
  stroke: currentColor;
  stroke-width: 1.5;
}

.r-map__legend {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(243,235,221,0.7);
}
.r-map__legend li { display: flex; align-items: center; gap: 8px; }
.r-map__legend__dot { width: 8px; height: 8px; border-radius: 50%; }
.r-map__legend__dot--active   { background: var(--saffron); }
.r-map__legend__dot--emerging { background: var(--canopy-lift); }
.r-map__legend__dot--longterm { background: var(--petrol-lift); }
.r-map__legend__dot--member   { background: var(--paper); width: 6px; height: 6px; }
.r-map__legend__dot--collaborator { background: var(--rose-lift); }
.r-map__legend__dot--ring-active   { box-shadow: 0 0 0 2px var(--saffron); margin: 0 3px; }
.r-map__legend__dot--ring-emerging { box-shadow: 0 0 0 2px var(--canopy-lift); margin: 0 3px; }
.r-map__legend__dot--ring-longterm { box-shadow: 0 0 0 2px var(--petrol-lift); margin: 0 3px; }

.r-map__credit {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  line-height: 1.6;
  color: rgba(243,235,221,0.6);
  margin-top: 12px;
}

/* The key. This is the accessible half of the pair — see the comment at the top
   of _includes/research-atlas.njk for why the SVG is aria-hidden and this is
   not. */
.r-map__key__title {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--saffron);
  margin: 0 0 16px;
}
.r-map__key__title--other {
  color: rgba(243,235,221,0.6);
  margin-top: 40px;
  margin-bottom: 6px;
}
/* Joel asked for the collaborators' heading in light petrol, 13 August 2026.
   8.30:1 on --ink. Worth knowing that this is the same blue the long-term
   pins and dots use, so the heading is a louder colour than the alumni one
   above it and is NOT keyed to the pink dots beneath it — it was asked for as
   emphasis, not as a colour code. */
.r-map__key__title--collab { color: var(--petrol-lift); }
.r-map__key__note {
  font-size: 13.5px;
  line-height: 1.6;
  color: rgba(243,235,221,0.6);
  margin: 0 0 16px;
}
.r-map__key__list { list-style: none; margin: 0; padding: 0; }
.r-map__key__list li { margin: 0; }

.r-map__key__item {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 9px 10px;
  margin-left: -10px;
  border-radius: 6px;
  text-decoration: none;
  color: rgba(243,235,221,0.8);
  transition: background .18s, color .18s;
}
/* Not scoped to `a`. It was, and the consequence was that every row without a
   card behind it — Bahía Negra, Presidente Hayes, Roraima, and all five alumni
   sites — stayed dark when its pin was hovered, which read as the map being
   broken. Eight of thirteen rows never lit. */
.r-map__key__item:hover,
.r-map__key__item:focus-visible,
.r-map__key__item.is-active {
  background: rgba(255,255,255,0.06);
  color: var(--paper);
}
.r-map__key__item--static { cursor: default; }

.r-map__key__dot {
  flex: 0 0 auto;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--saffron);
  transform: translateY(-1px);
}
.r-map__key__dot--emerging { background: var(--canopy-lift); }
.r-map__key__dot--longterm { background: var(--petrol-lift); }
.r-map__key__dot--member   { width: 6px; height: 6px; background: var(--paper); }
.r-map__key__dot--collaborator { background: var(--rose-lift); }
/* The key's echo of the map's core-and-ring. box-shadow rather than a border so
   the dot itself does not change size and the rows stay on one baseline; the
   margin gives the ring room so it does not touch the place name. */
.r-map__key__dot--ring-active   { box-shadow: 0 0 0 2px var(--saffron); margin: 0 3px; }
.r-map__key__dot--ring-emerging { box-shadow: 0 0 0 2px var(--canopy-lift); margin: 0 3px; }
.r-map__key__dot--ring-longterm { box-shadow: 0 0 0 2px var(--petrol-lift); margin: 0 3px; }
.r-map__key__name { flex: 1 1 auto; font-size: 15px; line-height: 1.4; }
/* The researcher whose work the site belongs to. Mono and quieter than the
   place, so the column still reads as a list of places first. Names are spelled
   as in _data/people.json — the same strings that render on /collective/. */
.r-map__key__who {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  color: rgba(243,235,221,0.6);
  text-align: right;
}
.r-map__key__ref {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  color: var(--saffron);
}

/* The card end of the link. :target covers the no-JS case — clicking a pin or a
   key row jumps to the card and it stays marked; .is-active is the JS hover. */
.r-proj:target,
.r-proj.is-active {
  border-color: rgba(232,160,23,0.55);
  background: rgba(255,255,255,0.07);
}

@media (prefers-reduced-motion: reduce) {
  .r-map__halo,
  .r-map__dot,
  .r-map__key__item { transition: none; }
}

/* =========================================================
   COLLABORATORS & FUNDERS — REMOVED 26 AUGUST 2026
   =========================================================
   The section moved off this page: the ten funders (plus TCD) are the
   homepage's closing band, and the four collaborators are "Key collaborators"
   on /collective/. See the note in research.njk where the markup used to be.

   About 150 lines went with it — .r-partners, __title, __block, __lead,
   __wall, __logo, __logo__link, __logo__mark, __logo__type, __logo__name and
   __where, plus their 720px overrides. The wall itself lives on as .logo-wall
   in styles.css, which is the global sheet because two pages now carry it.

   TWO OF THOSE RULES ARE GONE FOR GOOD RATHER THAN RENAMED, and it is worth
   saying which, because both encoded decisions:

     .r-partners__logo__mark   the white tile — fixed 112px height, 1px --rule
                               border, 16px/20px padding. Joel asked for the
                               marks out of the white boxes. What .logo-wall
                               keeps from it is the 120px pixel cap on the
                               image, which is the part that was load-bearing:
                               these are 2x assets and `max-width: 100%` would
                               silently render the whole wall at 1x.
     .r-partners__logo__type   the nameplate for a collaborator with no logo.
                               It had been unused since 14 August 2026, kept
                               against the next logo-less collaborator. All four
                               collaborators have a mark, and a wall with no
                               tiles has nowhere to put a nameplate anyway — a
                               name in the display face beside four real logos
                               would read as a fifth logo. If one arrives
                               without a mark, that is a new design question,
                               not a class to restore.

   The 1100px block below is untouched; nothing in it was ever about this
   section. */

@media (max-width: 1100px) {
  .r-section-head { grid-template-columns: 1fr; gap: 16px; }
  .r-lines__grid { grid-template-columns: 1fr 1fr; }
  .r-map__grid { grid-template-columns: 1fr; gap: 36px; }
  .r-map__svg { max-width: 620px; }
}
/* The charter goes two-up before anything else does. The cards hold a title of
   three or four words and nothing more, so four columns survive down to about
   860px — well past where the line cards have to fold. */
@media (max-width: 860px) {
  .r-charter__grid { grid-template-columns: 1fr 1fr; gap: 0 32px; }
}
@media (max-width: 720px) {
  .r-lines__grid,
  .r-projects__list { grid-template-columns: 1fr; }
  .r-hero { padding: 64px 0 48px; }
  .r-charter { margin-top: 40px; padding-top: 32px; }
  .r-charter__body { margin-bottom: 24px; }
  .r-proj__head { flex-direction: column; align-items: flex-start; gap: 8px; }
  .r-map { padding-top: 64px; }
  /* Five .r-partners overrides stood here until 26 August 2026 and went with
     the section — see the note above. */
}
/* One column only at the narrow end. Two columns of three-word titles still
   read fine at 480px and halve the height of the opening screen, which is the
   whole reason the bodies moved into dialogs. */
@media (max-width: 480px) {
  .r-charter__grid { grid-template-columns: 1fr; }
}

/* =========================================================
   IN-PAGE SECTION NAV
   =========================================================
   The bar itself is a shared component and lives in styles.css — it is on the
   homepage too since 13 August 2026, and was `.r-secnav` here until then.
   What stays with the page is this: anchor targets have to clear the site
   header AND the bar, or every jump from the header dropdown 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/research.css loads only here. */
html { scroll-padding-top: 142px; }
